为什么我的哈希函数失败了" ArithmeticException整数溢出"即使使用未经检查的数学

时间:2015-10-23 16:12:32

标签: clojure integer-arithmetic

我正在使用以下函数尝试创建一个字符串的64位哈希值,但即使我使用"未选中"它也会失败并出现ArithmeticException。算术运算符的版本。

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)

我在这里做错了什么?

2 个答案:

答案 0 :(得分:3)

在这里有一个提示:

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

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);
}

所以最后它从multiply内部类调用LongOps方法。

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;
}

<强> KABOOM!

所以我不知道这是一个错误还是想要的行为,但对我来说这看起来很奇怪。

所以我唯一可以建议的是,在clojure中使用未经检查的数学时,要始终记住键入你的值。

答案 1 :(得分:1)

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

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

;7096547112155234317

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