BigDecimal comparison?


#1

(BigDecimal(“0E-8”) == BigDecimal.ZERO) - false
(BigDecimal(“0E-8”).compareTo(BigDecimal.ZERO) == 0) - true
(BigDecimal(“0E-8”) == BigDecimal.ZERO.setScale(8)) - true

Is it a bug?


New operators
#2

The BigDecimal comparison functions are part of the JDK. Even if this behavior is a bug, it’s not a bug in Kotlin; you’ll see exactly the same with plain Java code.


#3

Ah, so ==, <, > compares object references for BigDecimals in Kotlin?
But in this case (BigDecimal(“0E-8”) == BigDecimal.ZERO.setScale(8)) - should be false always not?


#4

No. The == operator is compiled into a call of BigDecimal.equals(), and < and > are compiled into calls of BigDecimal.compareTo(), like for any other object. Both BigDecimal.equals() and BigDecimal.compareTo() are implemented in the JDK, and if you see any inconsistency, that’s a problem with the JDK implementation.


#5

Consequence of this is that you get the following:

val zero = BigDecimal(“0E-8”)

(zero < BigDecimal.ZERO) // false
(zero > BigDecimal.ZERO) // false
(zero == BigDecimal.ZERO) // false


#6

For BigDecimals equals checks both value and scale. d1.compareTo(d2) == 0 produces correct result and probably would be more meaningful for == operator.


#7

I would think if an object implements Comparable, == should rather use compareTo. Expectation would be that < and > have the same semantics as ==

Both Scala and Groovy gives true for BigDecimal(“0E-8”) == BigDecimal.ZERO so looks like they do it this way…


#8

FWIW, over the years there have been major user complaints arguing that Groovy should translate == to equals even for Comparable types (e.g. https://issues.apache.org/jira/browse/GROOVY-3364).


#9

Equals may be faster (see: String), compareTo isn’t tuned for equality testing.


#10

IMO == operator should be configurable. For most cases equals is fine, but there are classes where equals just doesn’t make sense as ==: BigDecimal, Array. There should be a way to alter default behaviour and call compareTo() for BigDecimals, Arrays.compare for Arrays, etc.


#11

I’m not sure how you envision this configurability, especially in the presence of generic classes. It would be really weird to have == work differently for t: T in Foo<T> where T is BigDecimal and for t: BigDecimal.


#12

I agree, it would be strange. Probably no good solution for that. May be it’s worth to implement BigDecimal wrapper to overcome this problem, like Scala did,