Data class with doubles as map keys


#1

Hello, i want to use following class as hash map key:

data class LxxWave(val battleState: BattleState, attackerName: String, victimName: String, val speed: Double) 

But Kotlin byte code viewer says, that in equals they will be compared without epsilon:

  ALOAD 0   INVOKEVIRTUAL lxx/waves/LxxWave.getSpeed ()D   ALOAD 2   INVOKEVIRTUAL lxx/waves/LxxWave.getSpeed ()D   DCMPG   IFEQ L2

So theoretically i cannot use data classes as map keys. Are there workarounds for that issue? Or it's not issue and i misunderstand semantics of DCMPG byte code?


#2

aleksey.zhidkov wrote:

Hello, i want to use following class as hash map key:

data class LxxWave(val battleState: BattleState, attackerName: String, victimName: String, val speed: Double)

But Kotlin byte code viewer says, that in equals they will be compared without epsilon:

    ALOAD 0
    INVOKEVIRTUAL lxx/waves/LxxWave.getSpeed ()D
    ALOAD 2
    INVOKEVIRTUAL lxx/waves/LxxWave.getSpeed ()D
    DCMPG
    IFEQ L2

So theoretically i cannot use data classes as map keys. Are there workarounds for that issue? Or it's not issue and i misunderstand semantics of DCMPG byte code?

You can, but you can never ever hope, that any hashing using epsilon in will work. Language agnostic. It can't work:

Imagine key containing nothing but a double, let eps=0.15, key1=0.00, key2=0.10, key3=0.20. With epsilon, key1 and key2 are the same, and so are key2 and key3. Therefore, key1 and key3 are the same, too. Some induction, and all keys are the same (except for NaN and Inf).

Epsilons not an option, the best you can do is probably to exclude doubles from hashing. For the computation, something like in
http://projectlombok.org/features/EqualsAndHashCode.html
can be done. Comparing via
http://homepages.inf.ed.ac.uk/kwxm/JVM/dcmpg.html
seems to be wrong as NaN!=NaN. Rather far from ideal.


#3

In my case if all other fields are equal and double fields are equal under some epsilon, then they are for sure a same "values". Also i have many data classes with doubles and this semantics, so i need easy/automatable workaround


#4

In my case if all other fields are equal and double fields are equal under some epsilon, then they are for sure a same "values". Also i have many data classes with doubles and this semantics, so i need easy/automatable workaround

If they're the same for you, then I guess you should make them exactly the same. I don't know enough about Kotlin to recommend the simplest way, I just wanted to show, that the epsilon-tolerant equals and hashing make no sense at all.

PS: Actually, I was wrong, not all double will be equal by induction. When they get big enough, adding epsilon is a no-op.