How to convert only the integer part of a BigDecimal to hex string?

10,993

Solution 1

Judging by your example you should use BigInteger instead of BigDecimal. This way you could use

new BigInteger("18446744073709551616").toString(16)

If you can't change type of original object convert it to BigInteger later in method

new BigDecimal("18446744073709551616").toBigInteger().toString(16);

Solution 2

Take into account that converting a decimal value into hex requires an exponent. You could get the hexadecimal String representing a numeric value using Formatter.

%A : The result is formatted as a hexadecimal floating-point number with a significand and an exponent
%X: The result is formatted as a hexadecimal integer

Use the %A conversion if you want to convert a decimal value:

System.out.println(String.format("%A", myBigDecimal));

Curiously, the code above is correct regarding the javadoc for Formatter, but there seems to be a related 9-year-old error in the javadocs, that has been fixed a few weeks ago in Java 8: 5035569 : (fmt) assertion error in Formatter for BigDecimal and %a. You can use the analog code below:

System.out.println(String.format("%A", myBigDecimal.doubleValue()));

EDIT
Judging by the value in your post, you don't really care about the fractional part. You could use the %X conversion in the pattern and just provide the BigInteger representation:

BigDecimal bd = new BigDecimal("18446744073709551616");
System.out.println(String.format("%X", bd.toBigInteger()));

Solution 3

Theoretically it is possible to represent BigDecimal as a hex string, simiolar to Double.toHexString

0x1.199999999999p+1

but AFAIK there is no standard way to do it and custom implementation will not be easy

Share:
10,993
becks
Author by

becks

Updated on June 05, 2022

Comments

  • becks
    becks almost 2 years

    I have a number of type BigDecimal, for example 18446744073709551616, and I want to convert it to hexadecimal value. I'm fine with truncating the fractional portion.

    Is there a way to do this instead of doing it manually?

  • becks
    becks about 11 years
    but for toString method it converts for example "16" to "10" not F as it should be in HEX representation. is there anything to get the correct one ?
  • Pshemo
    Pshemo about 11 years
    @becks it is correct result. Hex F is dec 15. Take a look a=10, b=11, c=12, d=13, e=14, f=15. So decimal 16 would be 10 hexadecimal.
  • becks
    becks about 11 years
    I get this error for the first one -- java.util.IllegalFormatConversionException: a != java.math.BigDecimal at java.util.Formatter$FormatSpecifier.failConversion(Formatter‌​.java:3999)
  • becks
    becks about 11 years
    I get this, but is there a method to convert it automatically to letters representation instead of 10 11 to 15 ? or I do it manually ?
  • Xavi López
    Xavi López about 11 years
    Yes, it's strange and might be related to a bug: 5035569 : (fmt) assertion error in Formatter for BigDecimal and %a (the javadoc for Formatter states it's possible to convert a BigDecimal). Use the form below, using doubleValue() and it will work.
  • Pshemo
    Pshemo about 11 years
    @becks What do you mean? It converts dec to hex correctly (with a,b,c,d,e,f) new BigInteger("30").toString(16) returns "1e" which is expected result.
  • Xavi López
    Xavi López about 11 years
    It is possible with Formatter and the %A conversion flag, see my answer.
  • becks
    becks about 11 years
    Thanks for the clarification. I used doublevalue for the above value in the code but the result was 0X1.0P64 instead of 0XFFFFFFFFFFFFFF80 is this expected ?
  • Pshemo
    Pshemo about 11 years
    since 16 * 1 + 1 * e = 16 + 14 = 30.
  • becks
    becks about 11 years
    I tried it for the value in my post but it converted it to 10000000000000000 instead of FFFFFFFFFFFFFF80 Is this expected ?
  • Evgeniy Dorofeev
    Evgeniy Dorofeev about 11 years
    I am getting java.util.IllegalFormatConversionException: a != java.math.BigDecimal for String.format("%A", new BigDecimal("1.1")
  • Xavi López
    Xavi López about 11 years
    There's an error in the javadocs. It turns out %A doesn't accept BigDecimal. Pass in BigDecimal.doubleValue().
  • Pshemo
    Pshemo about 11 years
    @becks why do you think 18446744073709551616 is FFFFFFFFFFFFFF80?
  • becks
    becks about 11 years
    sorry guys, I miss calculated it. Thanks a lot for the help :-)
  • Pavel Evstigneev
    Pavel Evstigneev over 7 years
    This will remove leading zeros
  • Pshemo
    Pshemo over 7 years
    @PavelEvstigneev Remember that purpose of BigInteger is to hold very big numbers which int or long can't hold. How many leading zeroes would you expect and why?
  • Pavel Evstigneev
    Pavel Evstigneev over 7 years
    I try to use it for MD5 and SHA1 hash sums, and if result should be starting with 0 then .toString(16) will remove leading zero
  • Pshemo
    Pshemo over 7 years
    @PavelEvstigneev in that case you are probably looking for solution like stackoverflow.com/questions/32186197/… (although I would use replace(' ','0') instead of replace(" ","0") for possible performance increase). If I am not mistaken BigInteger can't simply assume amount of needed leading zeroes since it isn't type with predefined size like int (32 bits) or long (64 bits). It could be nice to have method like toString(radix, predefinedSize) to handle cases like yours, but I am not aware of any of these in standard Java.
  • Pshemo
    Pshemo over 7 years
    @PavelEvstigneev This answer of Jon Skeet may also interest you: stackoverflow.com/a/10275845