Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there other gotchas similar to BigDecimal("1.0").equals(new BigDecimal("1") returning false?

I've just recently come across a behavior inside BigDecimal that I wasn't previously aware of. I've always used them as an alternative to double for areas where precision is important. For example in financial calculations.

However I recently came across this fact

new BigDecimal("1.0").equals(new BigDecimal("1")) == false

I have to admit I was surprised by this. I figure it is because the first has a scale of 1 while the second has a scale of 0, but still it seems counter-intuitive. I think the reason I've never run into it before is because we've always used fixed scale BigDecimals for financial calculations.

Checking the BigDecimal documentation I can see that says that compareTo() == 0 should be used to check for equality ignoring scale while that equals() compares both the value and the scale.

Are there any other similar gotchas I should be aware of when using BigDecimals with different scales?

like image 566
Tim B Avatar asked Apr 23 '15 13:04

Tim B


People also ask

What can I use instead of BigDecimal?

If you need to use division in your arithmetic, you need to use double instead of BigDecimal.

What is the difference between New BigDecimal and BigDecimal valueOf?

valueOf() has the more intuitive behaviour, while new BigDecimal(d) has the more correct one. Try both and see the difference.

How do I compare with BigDecimal?

compareTo(BigDecimal bg) method checks for equality of this BigDecimal and BigDecimal object bg passed as parameter. The method considers two equal BigDecimal objects even if they are equal in value irrespective of the scale.

How do you know if two BigDecimal values are equal?

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.


2 Answers

There is a value and a scale of the BigDecimal. Both need to be equal for the BigDecimals to be equal. From the java docs . . .

Unlike compareTo, this method considers two BigDecimal objects equal only if they are equal in value and scale (thus 2.0 is not equal to 2.00 when compared by this method).

https://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#equals(java.lang.Object)

like image 137
FriedSaucePots Avatar answered Oct 21 '22 22:10

FriedSaucePots


BigDecimal equals checks that the contents of the two BigDecimal object are the same. e.g. their toString() would be the same. Just as "1.0" and "1" are not equal, nor is new BigDecimal("1.0").equals(new BigDecimal("1")) as the unscaledValue() and getScale() are both different.

The catch is that while you knew that == wouldn't compare the contents and you might have been told .equals is the solution for String, it may not do what you intended for BigDecimal.

For compareTo it has to work on what is greater than or less than and since the values are neither greater than or less than they can only be equal (but not equals).

like image 31
Peter Lawrey Avatar answered Oct 21 '22 21:10

Peter Lawrey