According to the JavaDoc for BigDecimal, the compareTo function does not account for the scale during comparison.
Now I have a test case that looks something like this:
BigDecimal result = callSomeService(foo);
assertTrue(result.compareTo(new BigDecimal(0.7)) == 0); //this does not work
assertTrue(result.equals(new BigDecimal(0.7).setScale(10, BigDecimal.ROUND_HALF_UP))); //this works
The value I'm expecting the function to return is 0.7 and has a scale of 10. Printing the value shows me the expected result. But the compareTo() function doesn't seem to be working the way I think it should.
What's going on here?
BigDecimal precision is de facto unlimited since it is based on an int array of arbitrary length. Though operations with double are much faster than with BigDecimal this data type should never be used for precise values, such as currency.
equals() method checks for equality of a BigDecimal value with the object passed. This method considers two BigDecimal objects equal if only if they are equal in value and scale.
If you need to use division in your arithmetic, you need to use double instead of BigDecimal.
Using the compareTo Method Two BigDecimal objects that are equal in value but have a different scale (like 2.0 and 2.00) are considered equal by this method. Therefore, we can check BigDecimal. ZERO. compareTo(givenBdNumber) == 0 to decide if givenBdNumber has the value zero.
new BigDecimal(0.7) does not represent 0.7.
It represents 0.6999999999999999555910790149937383830547332763671875 (exactly).
The reason for this is that the double literal 0.7 doesn't represent 0.7 exactly.
If you need precise BigDecimal values, you must use the String constructor (actually all constructors that don't take double values will work).
Try new BigDecimal("0.7") instead.
The JavaDoc of the BigDecimal(double) constructor has some related notes:
The results of this constructor can be somewhat unpredictable. One might assume that writing
new BigDecimal(0.1)in Java creates aBigDecimalwhich 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 adouble(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.The
Stringconstructor, on the other hand, is perfectly predictable: writingnew BigDecimal("0.1")creates aBigDecimalwhich is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that theStringconstructor be used in preference to this one.When a
doublemust be used as a source for aBigDecimal, note that this constructor provides an exact conversion; it does not give the same result as converting thedoubleto aStringusing theDouble.toString(double)method and then using theBigDecimal(String)constructor. To get that result, use thestaticvalueOf(double)method.
So to summarize: If you want to create a BigDecimal with a fixed decimal value, use the String constructor. If you already have a double value, then BigDecimal.valueOf(double) will provide a more intuitive behaviour than using new BigDecimal(double).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With