user1514499 - 4 months ago 21

Java Question

I tried the following code. but getting different result when subtracting using BigDecimal.

`double d1 = 0.1;`

double d2 = 0.1;

System.out.println("double result: "+ (d2-d1));

float f1 = 0.1F;

float f2 = 0.1F;

System.out.println("float result: "+ (f2-f1));

BigDecimal b1 = new BigDecimal(0.01);

BigDecimal b2 = new BigDecimal(0.01);

b1 = b1.subtract(b2);

System.out.println("BigDecimal result: "+ b1);

Result:

`double result: 0.0`

float result: 0.0

BigDecimal result: 0E-59

I am still working on this. can anyone please clarify.

Answer

Interesting, the values appear to be equal and subtraction does give you zero, it appears to just be an issue with the printing code. The following code:

```
import java.math.BigDecimal;
public class Test {
public static void main(String args[]) {
BigDecimal b1 = new BigDecimal(0.01);
BigDecimal b2 = new BigDecimal(0.01);
BigDecimal b3 = new BigDecimal(0);
if (b1.compareTo(b2) == 0) System.out.println("equal 1");
b1 = b1.subtract(b2);
if (b1.compareTo(b3) == 0) System.out.println("equal 2");
System.out.println("BigDecimal result: "+ b1);
}
}
```

outputs *both* `equal`

messages, indicating that the values **are** the same and that you get **zero** when you subtract.

You could try to raise this as a bug and see what Oracle comes back with. It's likely they'll just state that `0e-59`

is still zero, so not a bug, or that the rather complex behaviour being described on the BigDecimal documentation page is working as intended. Specifically, the point that states:

There is a one-to-one mapping between the distinguishable BigDecimal values and the result of this conversion. That is, every distinguishable BigDecimal value (unscaled value and scale) has a unique string representation as a result of using toString. If that string representation is converted back to a BigDecimal using the BigDecimal(String) constructor, then the original value will be recovered.

That fact that the original value needs to be recoverable means that `toString()`

needs to generate a unique string for each scale, which is why you're getting `0e-59`

. Otherwise, converting the string *back* to a `BigDecimal`

may give you a different value (unscaled-value/scale tuple).

If you really *want* zero to show up as "0" regardless of the scale, you can use something like:

```
if (b1.compareTo(BigDecimal.ZERO) == 0) b1 = new BigDecimal(0);
```