Not sure if this is the right channel for this que...
# codereview
a
Not sure if this is the right channel for this question, but here we are:
Copy code
"hash code discrepancies" {
            val p0 = 0.0
            val p1 = -0.0
            (p0 == p1) shouldBe true
            val n0: Number = 0.0
            val n1: Number = -0.0
            n0.hashCode() shouldBe n1.hashCode()
        }

expected:<-2147483648> but was:<0>
Expected :-2147483648
Actual   :0
is there a reason what is essentially one and the same number has two different hashcodes?
a
Likely for the same reasons that the hash code is different in Java https://docs.oracle.com/javase/7/docs/api/java/lang/Double.html#equals%28java.lang.Object%29 > If d1 represents +0.0 while d2 represents -0.0, or vice versa, the equal test has the value false, even though +0.0==-0.0 has the value true. > This definition allows hash tables to operate properly.
gratitude thank you 1
e
floating point numbers have other fun behavior,
Copy code
val p0 = Double.NaN
println(p0.hashCode() == p0.hashCode())
println(p0 == p0)
println(p0 as Number == p0)
gratitude thank you 1
basically you want
+0.0 != -0.0
and
NaN == NaN
for
hashCode
reasons (otherwise
HashMap
is broken), while also wanting
+0.0 == -0.0
and
NaN != NaN
for IEEE 754 compliance
mind blown 1
so in Kotlin, you get one or the other, depending on how you look at it
a
why is HashMap broken?
0.0 == -0.0
so it would seem logical that both should have the same
hashCode
, correct?
e
in the case of NaN, it's never primitively
==
to itself, so you'll never be able to retrieve or remove it from a
HashMap
python has this issue actually:
Copy code
>>> d = {float('NaN'): 1, float('NaN'): 2}
>>> d
{nan: 1, nan: 2}
>>> d[float('NaN')]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: nan
a
but for a zero, surely
0.0
, and
-0.0
should be the same key, right?
e
and as there are many different types of signaling and non-signaling NaNs which should be distinguished in some circumstances,
hashCode
is defined in terms of the
toRawBits()
representation
+0.0
and
-0.0
have different representations
a
I should not care about how they are implemented, logically it is the same number, right?
e
sort of
Copy code
1 / +0.0 == +Infinity
1 / -0.0 == -Infinity
🤯 1
a
Oh I see your point. But is it relevant to Maps? Maybe. Thank you for detailed answers.