1

I want to retrieve the value of the bigDecimal with the exact value as it was instantiated here

BigDecimal balance = new BigDecimal(2300000870000000000067.7797);

The value I retrieve at the moment using balance is 2300000869999999975424. Can you please advise how can I retrieve it as 2300000870000000000067.7797 itself?

Jayesh Mulwani
  • 655
  • 6
  • 19
  • You can try to use `toString()` to get the exact value and then convert it to a number if you want to. – Maxouille Sep 18 '18 at 11:20
  • 3
    i think new BigDecimal("2300000870000000000067.7797"); – Ashvin solanki Sep 18 '18 at 11:20
  • Try using Strings instead of BigDecimal – guroosh Sep 18 '18 at 11:22
  • If it is possible for you, use `BigDecimal(String val)` : `new BigDecimal("2300000870000000000067.7797")` – LuCio Sep 18 '18 at 11:26
  • 2
    @Maxouille Simply wrong and misleading. What is the point of giving advice when you don't know the subject? – GhostCat Sep 18 '18 at 11:29
  • FYI Java can not save/display the double `2300000870000000000067.7797`, so the compiler is generating code for `new BigDecimal(2300000869999999975424)` - there is no way to get the first value back, unless you use String instead of double to create the BigDecimal (obviously there is no point to do so just to retrieve the String back (if not doing operations with the BigDecimal)...) – user85421 Sep 18 '18 at 11:51
  • @GhostCat this problem has the added complexity of a literal that cannot fit in a double, so not really a duplicate. – Jan Larsen Sep 18 '18 at 11:52
  • but isn't the **first** (haven't checked the 2nd) duplicate question just about a literal that cannot fit (correctly) in a double? – user85421 Sep 18 '18 at 11:54
  • 1
    The point is: when you are **not** using the String-based constructor, you give up on precision anyway. As the answers and the DUP question suggests: you absolutely do not want the double-taking constructor. – GhostCat Sep 18 '18 at 11:56
  • The subject of literals that don't fit in doubles is separate from the subject of doubles that dont fit in BigDecimal. But they are related I guess. If you set a double to 0.1 and print it, you will get "0.1" even if the BigDecimal constructor would mess it up. – Jan Larsen Sep 18 '18 at 11:58

3 Answers3

3

You have used java.math.BigDecimal.BigDecimal(double val) constructor.

From JavaDoc:

java.math.BigDecimal.BigDecimal(double val)


Translates a double into a BigDecimal which is the exact decimal representation of the double's binary floating-point value. The scale of the returned BigDecimal is the smallest value such that (10scale × val) is an integer. 

Notes: 
1. The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding. 
2. The String constructor, on the other hand, is perfectly predictable: writing new BigDecimal("0.1") creates a BigDecimal which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that the String constructor be used in preference to this one. 
3. When a double must be used as a source for a BigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting the double to a String using the Double.toString(double) method and then using the BigDecimal(String) constructor. To get that result, use the static valueOf(double) method. 

Here First point suggests that :

The results of this constructor can be somewhat unpredictable. One might assume that writing new BigDecimal(0.1) in Java creates a BigDecimal which is exactly equal to 0.1 (an unscaled value of 1, with a scale of 1), but it is actually equal to 0.1000000000000000055511151231257827021181583404541015625. This is because 0.1 cannot be represented exactly as a double (or, for that matter, as a binary fraction of any finite length). Thus, the value that is being passed in to the constructor is not exactly equal to 0.1, appearances notwithstanding.

Second point suggests to use the constructor with string argument for exact value.

This is the reason for difference of value.

Raj
  • 707
  • 6
  • 23
0

The java doc itself suggest about BigDecimal(Double val):

The results of this constructor can be somewhat unpredictable.

You should use the following instead:

BigDecimal balance = new BigDecimal("2300000870000000000067.7797");
S.K.
  • 3,597
  • 2
  • 16
  • 31
0

You are trying to use a literal number that cannot fit in a double which has a maximum of 15 decimals precision - probably why you want to use BigDecimal in the first place. So your number is converted to the most acurate representation in a double before initialising BigDecimal. Then the BigDecimal contructor compounds the error by messing up the already messed up double.

You will have to represent numbers as Strings to get that precision.

    double x = 2300000870000000000067.7797d;
    System.out.println("double:"+x);        
    BigDecimal balance = new BigDecimal(2300000870000000000067.7797);
    System.out.println("balance:"+balance);
    BigDecimal stringbased = new BigDecimal("2300000870000000000067.7797");
    System.out.println("stringbased:"+stringbased);

Prints

double:2.30000087E21
balance:2300000869999999975424
stringbased:2300000870000000000067.7797
Jan Larsen
  • 831
  • 6
  • 13