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

bit*_*ops 18 clojure

它似乎一直都在发生.例如:

(apply * (range 1 101))
Run Code Online (Sandbox Code Playgroud)

给了我错误

ArithmeticException integer overflow  clojure.lang.Numbers.throwIntOverflow (Numbers.java:1374)
Run Code Online (Sandbox Code Playgroud)

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

(1..100).reduce(:*)
Run Code Online (Sandbox Code Playgroud)

产生预期的结果

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
Run Code Online (Sandbox Code Playgroud)

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

Ste*_*ang 37

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

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

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


Nie*_*lsK 6

Ruby具有自动提升计算,当结果溢出其类型时,会更改为更大的位类型数.由于性能方面的考虑,从Clojure的1.3提高计算不会自动提升,你需要考虑到,如果一个计算可以溢出,或使用自动推进的数学函数(+',-',*',/')如果性能不会是一个问题.


don*_*gpf 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))

参考:Clojure 1.3 Numerics的文档