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 aBigDecimal
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 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
String
constructor, on the other hand, is perfectly predictable: writingnew BigDecimal("0.1")
creates aBigDecimal
which is exactly equal to 0.1, as one would expect. Therefore, it is generally recommended that theString
constructor be used in preference to this one.When a
double
must be used as a source for aBigDecimal
, note that this constructor provides an exact conversion; it does not give the same result as converting thedouble
to aString
using theDouble.toString(double)
method and then using theBigDecimal(String)
constructor. To get that result, use thestatic
valueOf(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