2

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?

T.J. Crowder
  • 879,024
  • 165
  • 1,615
  • 1,639
becks
  • 2,468
  • 7
  • 29
  • 62
  • refer cource code [here](http://www.docjar.com/html/api/java/math/BigDecimal.java.html) – chiru Mar 25 '13 at 13:16

3 Answers3

9

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);
Pshemo
  • 113,402
  • 22
  • 170
  • 242
  • 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 ? – becks Mar 25 '13 at 13:35
  • @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. – Pshemo Mar 25 '13 at 13:38
  • 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 ? – becks Mar 25 '13 at 13:42
  • @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. – Pshemo Mar 25 '13 at 13:46
  • since **16** * `1` + **1** * `e` = 16 + 14 = 30. – Pshemo Mar 25 '13 at 13:54
  • I tried it for the value in my post but it converted it to 10000000000000000 instead of FFFFFFFFFFFFFF80 Is this expected ? – becks Mar 25 '13 at 13:54
  • 1
    @becks why do you think `18446744073709551616` is `FFFFFFFFFFFFFF80`? – Pshemo Mar 25 '13 at 14:08
  • sorry guys, I miss calculated it. Thanks a lot for the help :-) – becks Mar 25 '13 at 14:14
  • 1
    This will remove leading zeros – Pavel Evstigneev Jan 25 '17 at 12:38
  • @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? – Pshemo Jan 25 '17 at 14:13
  • 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 – Pavel Evstigneev Jan 25 '17 at 16:11
  • @PavelEvstigneev in that case you are probably looking for solution like http://stackoverflow.com/questions/32186197/converting-hex-to-binary-with-leading-zeros (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 Jan 25 '17 at 17:10
  • @PavelEvstigneev This answer of Jon Skeet may also interest you: http://stackoverflow.com/a/10275845 – Pshemo Jan 25 '17 at 17:23
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()));
Xavi López
  • 26,413
  • 11
  • 94
  • 146
  • 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 Mar 25 '13 at 13:41
  • Yes, it's strange and might be related to a bug: [5035569 : (fmt) assertion error in Formatter for BigDecimal and %a](http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5035569) (the javadoc for `Formatter` states it's possible to convert a `BigDecimal`). Use the form below, using `doubleValue()` and it will work. – Xavi López Mar 25 '13 at 13:42
  • 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 ? – becks Mar 25 '13 at 13:52
  • 1
    I am getting java.util.IllegalFormatConversionException: a != java.math.BigDecimal for String.format("%A", new BigDecimal("1.1") – Evgeniy Dorofeev Mar 25 '13 at 13:57
  • 1
    There's an error in the javadocs. It turns out `%A` doesn't accept `BigDecimal`. Pass in `BigDecimal.doubleValue()`. – Xavi López Mar 25 '13 at 13:58
1

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

Evgeniy Dorofeev
  • 124,221
  • 27
  • 187
  • 258
  • It is possible with `Formatter` and the `%A` conversion flag, see [my answer](http://stackoverflow.com/a/15616261/851811). – Xavi López Mar 25 '13 at 13:49