Search code examples
clojurescript

ClojureScript floats hashed as ints


At first I thought this is a bug, but looking at the source code it's clearly intentional. Does anybody know why this is being done? It's inconsistent with Clojure and a subtle source for bugs.

(hash 1)   ; => 1
(hash 1.5) ; => 1

https://github.com/clojure/clojurescript/blob/master/src/main/cljs/cljs/core.cljs#L985

(defn hash
  "Returns the hash code of its argument. Note this is the hash code
   consistent with =."
  [o]
  (cond
    (implements? IHash o)
    (bit-xor (-hash ^not-native o) 0)

    (number? o)
    (if (js/isFinite o)
      (js-mod (Math/floor o) 2147483647)
      (case o
        Infinity
        2146435072
        -Infinity
        -1048576
        2146959360))
  ...))

Solution

  • JavaScript has only one number type: 64-bit float between -(2^53)-1 and (2^53)-1. However, bitwise operations work on 32-bit signed integers. So, a lossy conversion is needed, when a float is converted to a hash that works with bitwise operators. The magic number 2147483647 for the modulo operation in core.cljs/hash is the maximum integer representable through a 32bit signed number. Note that there is also special handling for values Infinity and -Infinity.