如何在Clojure中避免“ArithmeticException整数溢出”?

时间:2012-01-07 05:27:23

标签: clojure

似乎一直都在发生。例如:

(apply * (range 1 101))

给我错误

ArithmeticException integer overflow  clojure.lang.Numbers.throwIntOverflow (Numbers.java:1374)

在Ruby 1.9.2中(概念上)等效代码,

(1..100).reduce(:*)

产生所需的

结果
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000

显然这两种语言在引擎盖下是完全不同的,但似乎他们都应该能够毫无问题地处理这种计算。我在这里做错了吗?或者我的理解不正确?

6 个答案:

答案 0 :(得分:37)

您需要使用某种形式的BigInteger。

尝试(apply *' (range 1 101))

(见http://dev.clojure.org/display/doc/Documentation+for+1.3+Numerics - 显然这会在溢出时自动升级?)

答案 1 :(得分:6)

Ruby具有自动提升计算功能,当结果溢出其类型时,会更改为更大的位类型数。由于性能方面的考虑,Clojure 1.3上的计算不会自动提升,您需要考虑计算是否会溢出,或者使用其中一个自动提升数学函数(+',{{1 }},-'*')如果性能不是问题。

答案 2 :(得分:6)

从Clojure 1.3中,你应该明确地将Integer(或Long)强制转换为BigInt,否则当数字太大时会出现“ArithmeticException integer overflow”错误。

有三种解决方案,请选择您喜欢的解决方案:

  • 使用其中一项自动推广数学函数:+', -', *', /', inc', dec'

    示例:(apply *' (range 1 101))

  • 使用BigInt类型强制转换功能

    示例:(apply * (range (bigint 1) 101))

  • 更改为BigInt数字文字

    示例:(apply * (range 1N 101))

参考:Documentation for Clojure 1.3 Numerics

答案 3 :(得分:1)

偶然发现了同样的情况。对我来说使用" 1.0"而不是" 1"做了伎俩。

(apply * (range 1.0 1000))

作为documented,浮点数和小数点之间存在差异。

答案 4 :(得分:0)

我不知道Clojure,但看起来它使用32位或64位整数来进行计算。 32位有符号整数的最大值为2^31 - 1(超过2 * 10 ^ 9)。 64位整数的最大值为2^64 - 1(有点超过4 * 10 ^ 18)。你从Ruby获得的价值要高得多。

显然,Ruby正在使用其他一些数字表示法。

答案 5 :(得分:0)

1.3.0中的

(申请*(范围1N 101N)); clojure.lang.BigInt

(申请*(范围1M 101M)); java.math.BigDecimal