Uploaded image for project: 'Scala Programming Language'
  1. Scala Programming Language
  2. SI-5640

Scala hash code of some Double objects is different when it is seen as Double and when it is seen as Any

    Details

      Description

      The same object d below has different scala hash code
      when it is seen as static type Double and when it is seen as static type Any .

      def testHashHash {
        val d = (BigInt(1) << 64).toDouble
        val a: Any = d
        println("d.hashCode="+d.hashCode)
        println("d.##="+d.##)
        println("a.##="+a.##)
        assert(d.## == a.##)
      }
      

      This is because BoxesRunTime.hashFromDouble(java.lang.Double n) and ScalaRunTime.hash(dv: Double) don't match.

        Attachments

          Activity

          Hide
          magarcia Miguel Garcia added a comment -

          Minimized further:

          scala> val d = (BigInt(1) << 64).toDouble
          d: Double = 1.8446744073709552E19
           
          scala> val a: Any = d
          a: Any = 1.8446744073709552E19
           
          scala> scala.Double.box(d).hashCode()
          res0: Int = 1139802112
           
          scala> scala.runtime.ScalaRunTime.hash(d)
          res1: Int = 1602224128
           
          scala> scala.runtime.ScalaRunTime.hash(a)
          res2: Int = 1139802112
          

          Show
          magarcia Miguel Garcia added a comment - Minimized further: scala> val d = (BigInt(1) << 64).toDouble d: Double = 1.8446744073709552E19   scala> val a: Any = d a: Any = 1.8446744073709552E19   scala> scala.Double.box(d).hashCode() res0: Int = 1139802112   scala> scala.runtime.ScalaRunTime.hash(d) res1: Int = 1602224128   scala> scala.runtime.ScalaRunTime.hash(a) res2: Int = 1139802112
          Hide
          dgruntz Dominik Gruntz added a comment -

          Actually, a and d have the same hashCode. It is ## which returns different results than hashCode for boxed numeric types (and for null) as documented.

          scala> val d = (BigInt(1) << 64).toDouble
          d: Double = 1.8446744073709552E19
           
          scala> val a: Any = d
          a: Any = 1.8446744073709552E19
           
          scala> d.hashCode
          res22: Int = 1139802112
           
          scala> a.hashCode
          res23: Int = 1139802112
          

          So if this behavior is changed, do not forget to update the docs of ## as well.

          Show
          dgruntz Dominik Gruntz added a comment - Actually, a and d have the same hashCode . It is ## which returns different results than hashCode for boxed numeric types (and for null ) as documented. scala> val d = (BigInt(1) << 64).toDouble d: Double = 1.8446744073709552E19   scala> val a: Any = d a: Any = 1.8446744073709552E19   scala> d.hashCode res22: Int = 1139802112   scala> a.hashCode res23: Int = 1139802112 So if this behavior is changed, do not forget to update the docs of ## as well.
          Hide
          extempore Paul Phillips added a comment - - edited

          ## isn't supposed to give different answers based on the static type of the argument.
          That (x: Any).## != (x: Foo).## is definitely a bug.  This is already recognized in the doc for ##.
          "if two value type instances compare as true, then ## will produce the same hash value for each of them."
          

          Show
          extempore Paul Phillips added a comment - - edited ## isn't supposed to give different answers based on the static type of the argument. That (x: Any).## != (x: Foo).## is definitely a bug. This is already recognized in the doc for ##. "if two value type instances compare as true, then ## will produce the same hash value for each of them."
          Hide
          extempore Paul Phillips added a comment -

          Oh yeah, I forgot how irreconcilable this situation is. What I said is only true up to about 16 bits of width, then it becomes impossible.

          Show
          extempore Paul Phillips added a comment - Oh yeah, I forgot how irreconcilable this situation is. What I said is only true up to about 16 bits of width, then it becomes impossible.
          Hide
          extempore Paul Phillips added a comment -

          58bb2d1bd2

          Show
          extempore Paul Phillips added a comment - 58bb2d1bd2
          Hide
          dgruntz Dominik Gruntz added a comment -

          runtime.BoxesRunTime.hashFromDouble(d) still returns the wrong value. Should that also be fixed, or is this method no longer used anywhere (in the context of ##)?
          I claim that hashFromDouble should also check whether the argument can be represented correctly within a float and then return that hashCode.

          scala> runtime.BoxesRunTime.hashFromNumber(d)
          res16: Int = 1139802112
           
          scala> runtime.BoxesRunTime.hashFromNumber(d.toFloat)
          res17: Int = 1602224128
           
          scala> d == d.toFloat
          res18: Boolean = true
          

          Show
          dgruntz Dominik Gruntz added a comment - runtime.BoxesRunTime.hashFromDouble(d) still returns the wrong value. Should that also be fixed, or is this method no longer used anywhere (in the context of ## )? I claim that hashFromDouble should also check whether the argument can be represented correctly within a float and then return that hashCode. scala> runtime.BoxesRunTime.hashFromNumber(d) res16: Int = 1139802112   scala> runtime.BoxesRunTime.hashFromNumber(d.toFloat) res17: Int = 1602224128   scala> d == d.toFloat res18: Boolean = true
          Hide
          extempore Paul Phillips added a comment -

          Sorry, I'm doing things in a bit of a rush. I see there are redundant implementations in BoxesRunTime and ScalaRunTime, don't know why. If you are up for sending a pull request I'd be thrilled.

          Show
          extempore Paul Phillips added a comment - Sorry, I'm doing things in a bit of a rush. I see there are redundant implementations in BoxesRunTime and ScalaRunTime, don't know why. If you are up for sending a pull request I'd be thrilled.
          Hide
          dgruntz Dominik Gruntz added a comment -

          really? here it is: b5919100e7

          Show
          dgruntz Dominik Gruntz added a comment - really? here it is: b5919100e7

            People

            • Assignee:
              extempore Paul Phillips
              Reporter:
              nadezhin Dmitry Nadezhin
            • Votes:
              0 Vote for this issue
              Watchers:
              6 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved: