为什么即使使用未经检查的数学运算,我的哈希函数也会失败 "ArithmeticException integer overflow"

Why does my hash function fail with "ArithmeticException integer overflow" even when using unchecked math

我正在使用以下函数尝试创建字符串的 64 位散列,但它失败并出现 ArithmeticException,即使我使用的是 "unchecked" 版本的算术运算符。

user> (reduce (fn [h c]
                (unchecked-add (unchecked-multiply h 31) (long c)))
              1125899906842597
              "hello")
ArithmeticException integer overflow   clojure.lang.Numbers.throwIntOverflow (Numbers.java:1388)

我做错了什么?

这里有个提示:

无论出于何种原因,此处函数中的第一个参数都被视为整数。添加类型提示有助于解决这个问题:

user> (reduce (fn [^long h c]
                (unchecked-add (unchecked-multiply h 31) (long c)))
              1125899906842597
              "hello")
7096547112155234317

更新: 此外:它看起来来自 unchecked-multiply

user> (reduce (fn [h c]
                (unchecked-add (unchecked-multiply ^long h 31) (long c)))
              1125899906842597
              "hello")
7096547112155234317

我会做一些额外的研究,并在这里更新,以防有任何新信息

更新 2: 好的,这就是我发现的:

https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/Numbers.java 查看 clojure 的文档 我们可以看到以下内容:

我们的案例

static public Number unchecked_multiply(Object x, long y){return multiply(x,y);}

导致:

static public Number multiply(Object x, long y){
    return multiply(x,(Object)y);
}

然后:

static public Number multiply(Object x, Object y){
    return ops(x).combine(ops(y)).multiply((Number)x, (Number)y);
}

所以最后它从 LongOps 内部 class.

调用 multiply 方法
final public Number multiply(Number x, Number y){
    return num(Numbers.multiply(x.longValue(), y.longValue()));
}

所以最后它引导我们进行简单的(已检查?)乘法:

static public long multiply(long x, long y){
  if (x == Long.MIN_VALUE && y < 0)
        return throwIntOverflow();
    long ret = x * y;
    if (y != 0 && ret/y != x)
        return throwIntOverflow();
    return ret;
}

轰隆隆!

所以我不知道这是错误还是预期的行为,但我觉得它真的很奇怪。

所以我唯一可以建议的是,在 clojure 中使用未经检查的数学时,请始终记住输入提示您的值。

您可以通过避免函数调用来获得您想要的行为:

(loop [h 1125899906842597
       cs "hello"]
  (let [c (first cs)]
    (if c
      (recur (unchecked-add (unchecked-multiply h 31) (long c))
             (rest cs))
      h)))

;7096547112155234317

为什么会这样,我不知道。