3

I have a need to compare two DoubleArrays in order to determine if they have the same values in the same order. To do so I have used the contentEquals extension function, however, it treats 0 and -0 as two different values (comparing them with == treats them the same).

For example:

val x = doubleArrayOf(1.0,0.0,-0.0)
val y = doubleArrayOf(1.0,0.0, 0.0)

x[0] == y[0] // true
x[1] == y[1] // true
x[2] == y[2] // true

x contentEquals y // false

Defining an extension function to do pairwise comparison myself,

infix fun DoubleArray.reallyEqual(other:DoubleArray) = (this.size == other.size) && this.zip(other).all {it.first == it.second}

x reallyEqual y // true

produces the expected result.

I am not sure if this is a bug, or if this is really the intended result, but it is a surprise as the individual equal tests compare true.

Looking at the source code, we can understand why this is this way. The contentEquals function delegates to java.util.Arrays::equals

/**
 * Returns `true` if the two specified arrays are *structurally* equal to one another,
 * i.e. contain the same number of the same elements in the same order.
 */
@SinceKotlin("1.1")
@kotlin.internal.InlineOnly
public inline infix fun DoubleArray.contentEquals(other: DoubleArray): Boolean {
    return java.util.Arrays.equals(this, other)
}

and that method delegates to Double::equals which considers these to be different

Two doubles d1 and d2 are considered equal if:

new Double(d1).equals(new Double(d2)) 

(Unlike the == operator, this method considers NaN equals to itself, and 0.0d unequal to -0.0d.)

Is this the intended behavior, or is the behavior that I am expecting the intended? I am not sure where bugs/feature requests for Kotlin are supposed to be reported, and this may belong there. If this is the intended behavior, perhaps a second method which delegates to == instead of Double::equals should be included in the standard library. At very least, a note in the documentation that this method relies on Double::equals instead of == and that the behavior is different.

Disclaimer: I am aware of the risks with precision when comparing double values with equality. Eventually, I will try to refactor my code so it doesn't rely on equality, but for now, it works with equality tests. This isn't a question about how to compare two arrays of doubles in general.

Matthew
  • 7,440
  • 1
  • 24
  • 49
  • 3
    Here you can report bugs or issue feature requests: https://youtrack.jetbrains.com/issues/KT – s1m0nw1 Feb 19 '18 at 23:32
  • Well, if you care about precision thing you should consider using BigDecimal and compareTo instead of double. – asm0dey Feb 20 '18 at 06:13
  • See: https://docs.oracle.com/javase/7/docs/api/java/lang/Double.html#equals%28java.lang.Object%29 and https://stackoverflow.com/questions/14771328/java-signed-zero-and-boxing – Jim Andreas Feb 20 '18 at 11:20
  • How do you override hashCode in this case? The standard behavior is not inconsistent with the equals contract. – duffymo Oct 23 '20 at 22:59

0 Answers0