我正在运行Clojure 1.4.0。为什么如果我添加Integer/MAX_VALUE
和1,我会得到一个Long,但如果我将Integer/MAX_VALUE
添加到自身,我会得到一个例外?
=> (def one 1)
=> (class one)
java.lang.Integer
=> (def max-plus-one (+ Integer/MAX_VALUE one))
=> max-plus-one
2147483648
=> (class max-plus-one)
java.lang.Long
=> (+ Integer/MAX_VALUE Integer/MAX_VALUE)
java.lang.ArithmeticException: integer overflow (NO_SOURCE_FILE:0)
它们不应该以同样的方式行事吗?为什么添加两个MAX_VALUE
值会溢出但添加1不会?
我见过this SO question,但他们的行为与我不同。
答案 0 :(得分:7)
这很奇怪,我在Ubuntu 12.04 64bit上看到了Clojure 1.4.0和Java(TM)SE运行时环境(版本1.7.0_06-b24)的不同结果:
user=> *clojure-version*
{:major 1, :minor 4, :incremental 0, :qualifier nil}
user=> (+ Integer/MAX_VALUE Integer/MAX_VALUE)
4294967294
user=> (type 1)
java.lang.Long
user=> (def max-plus-one (+ Integer/MAX_VALUE one))
#'user/max-plus-one
user=> max-plus-one
2147483648
user=> (type max-plus-one)
java.lang.Long
user=> (+ Integer/MAX_VALUE Integer/MAX_VALUE)
4294967294
您可以随时查看Java classes which clojure.core uses for numerics,了解功能的实施方式:
+运算符的实现:
(defn +
"Returns the sum of nums. (+) returns 0. Does not auto-promote
longs, will throw on overflow. See also: +'"
{:inline (nary-inline 'add 'unchecked_add)
:inline-arities >1?
:added "1.2"}
([] 0)
([x] (cast Number x))
([x y] (. clojure.lang.Numbers (add x y)))
([x y & more]
(reduce1 + (+ x y) more)))
添加longs的Java实现:
final public Number add(Number x, Number y){
return num(Numbers.add(x.longValue(),y.longValue()));
}
编辑:使用Clojure 1.2.1测试 我已经使用Clojure 1.2.1进行了快速测试,并且通过该版本的Clojure,我得到了您的行为。
user=> *clojure-version*
{:major 1, :minor 2, :incremental 1, :qualifier ""}
user=> (def one 1)
#'user/one
user=> (class 1)
java.lang.Integer
user=> (def max-plus-one (+ Integer/MAX_VALUE one))
#'user/max-plus-one
user=> max-plus-one
2147483648
user=> (class max-plus-one)
java.lang.Long
user=> (+ Integer/MAX_VALUE Integer/MAX_VALUE)
java.lang.ArithmeticException: integer overflow (NO_SOURCE_FILE:0)
我会说您使用Clojure 1.2.x进行了测试,而不是使用1.4.0进行测试。你的REPL中* clojure-version *的价值是多少?
答案 1 :(得分:4)
看起来你有答案,但这里有一些其他有趣的观点:
java(所有版本)和clojure(> 1.3.0)默认行为在他们的行为上有不同的溢出
在java中
(Long.MAX_VALUE + 1) == Long.MIN_VALUE
(Integer.MAX_VALUE + 1) == Integer.MIN_VALUE
// cast required to avoid promoting to int
(Byte.MAX_VALUE + (byte)1) == Byte.MIN_VALUE
这是因为默认情况下,算术在jvm
上包装in clojure(> 1.3.0)
(inc Long.MAX_VALUE)
=> ArithmeticOverflow
(inc Integer/MAX_VALUE)
=> a long with value Integer/MAX_VALUE + 1
(int (inc Integer/MAX_VALUE))
=> IllegalArgumentException Value
out of range for int: 2147483648
clojure确实有一些行为类似java
的ops版本(unchecked-inc Long.MAX_VALUE) => Long.MIN_VALUE
您可以将*unchecked-math*
设置为true
(set! *unchecked-math* true)
(inc Long/MAX_VALUE)
=> (Long.MIN_VALUE)
(int (inc Integer/MAX_VALUE))
=> (Integer.MIN_VALUE) of type Integer
还有很多其他有趣的(unchecked-*)
操作。
答案 2 :(得分:1)
从版本1.3.0开始,Clojure将Longs用于所有原始数字。你只需要使用更大的数字来获得溢出。
(def max-plus-one (+ Long/MAX_VALUE one))