BigDecimal equals() versus compareTo()
Asked Answered
F

4

204

Consider the simple test class:

import java.math.BigDecimal;

/**
 * @author The Elite Gentleman
 *
 */
public class Main {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        BigDecimal x = new BigDecimal("1");
        BigDecimal y = new BigDecimal("1.00");
        System.out.println(x.equals(y));
        System.out.println(x.compareTo(y) == 0 ? "true": "false");
    }

}

You can (consciously) say that x is equal to y (not object reference), but when you run the program, the following result shows:

false
true

Question: What's the difference between compareTo() and equals() in BigDecimal that compareTo can determine that x is equal to y?

PS: I see that BigDecimal has an inflate() method on equals() method. What does inflate() do actually?

Fabric answered 22/7, 2011 at 7:56 Comment(2)
Ad inflate(): it's not part of the public API because it only manipulates the internal representation and has no visible effect to the "outside". So unless you really want to study the implementation of BigDecimal in-depth, I'd suggest you ignore this method.Stepmother
A short explanation and source code snippets can be found hereCreamy
S
285

The answer is in the JavaDoc of the equals() method:

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).

In other words: equals() checks if the BigDecimal objects are exactly the same in every aspect. compareTo() "only" compares their numeric value.

As to why equals() behaves this way, this has been answered in this SO question.

Stepmother answered 22/7, 2011 at 7:59 Comment(9)
That's a very tricky portion of BigDecimal if you don't read the JavaDoc carefully. :) - We got some strange bugs from this until we realized the difference.Dextroglucose
Many parts of the standard API happen to act "unintuitively", when the intuitive thing would not be correct. BigDecimal is one such thing. Therefore one should always check the JavaDoc. At least once your find out something strange is going on.Stepmother
Funny. After reading your answer I just checked Comparable and it states that consistence with equals "is strongly recommended (but not required)"Cottle
@Cottle - it is important to understand why it is correct that this inconsistency should exist for BigDecimal ...Declarant
I've asked why: #14102583Affectional
@StephenC I think it's incorrect that this inconsistency exists.Prostitution
@MattR: There are two reasons for the behavior. First of all, the values 1.20 and 1.2 may represent the same value, but they do not behave identically in all contexts. For example, calling toString() on them will yield different values. That may be a sufficient difference to regard them as unequal. Secondly, it the two values compare as equal, then the values from the hash function would have to match as well. The way BigDecimal values 1.20 and 1.2 are stored, however, is sufficiently different that computing matches hash values would be tricky.Saturniid
@Saturniid We...discussed this four years ago: #14102583Prostitution
The longer I work with java.lang.BigDecimal the more I regret not using the money on my system as an int/long representation of the centsCringle
D
2

I see that BigDecimal has an inflate() method on equals() method. What does inflate() do actually?

Basically, inflate() calls BigInteger.valueOf(intCompact) if necessary, i.e. it creates the unscaled value that is stored as a BigInteger from long intCompact. If you don't need that BigInteger and the unscaled value fits into a long BigDecimal seems to try to save space as long as possible.

Dextroglucose answered 22/7, 2011 at 8:18 Comment(2)
I have no idea what you wrote (especially with the last sentence).Fabric
@The Elite Gentlement The last sentence should just say that internally BigDecimal keeps its unscaled value in a long as well as a BigInteger. If the BigInteger is not needed internally it is not created but if it is needed (e.g. when equals encounters an inflated and a non-inflated BigDecimal) inflate()` is used to create it. - To sum it up: inflate() handles internal conversions if necessary and since it is private it shouldn't matter for users of the class.Dextroglucose
W
2

I believe that the correct answer would be to make the two numbers (BigDecimals), have the same scale, then we can decide about their equality. For example, are these two numbers equal?

1.00001 and 1.00002

Well, it depends on the scale. On the scale 5 (5 decimal points), no they are not the same. but on smaller decimal precisions (scale 4 and lower) they are considered equal. So I suggest make the scale of the two numbers equal and then compare them.

Whorehouse answered 11/12, 2019 at 6:32 Comment(0)
L
-18

You can also compare with double value

BigDecimal a= new BigDecimal("1.1"); BigDecimal b =new BigDecimal("1.1");
System.out.println(a.doubleValue()==b.doubleValue());
Lelandleler answered 15/9, 2017 at 11:39 Comment(3)
Please avoid this solution as much as possible. Even doubles should be compared with "epsilon". There is no sense to have BigDecimal and compare it as doubles..there is very high probability you will shoot your own leg.Sportsman
Douuble values must be compared using epsillonsPhotography
The crutches even on stackoverflowBailiff

© 2022 - 2024 — McMap. All rights reserved.