我正在使用以下函数尝试创建一个字符串的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)
我在这里做错了什么?
答案 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
为什么会这样,我不知道。