Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I avoid "ArithmeticException integer overflow" in Clojure?

Tags:

It seems to happen all the time. For example:

(apply * (range 1 101)) 

gives me the error

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

While in Ruby 1.9.2 the (conceptually) equivalent code,

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

produces the desired result of

93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000 

Obviously the two languages are quite different under the hood but it seems like they should both be able to handle this calculation without issue. Am I doing something wrong here? Or do I have an incorrect understanding?

like image 560
bitops Avatar asked Jan 07 '12 05:01

bitops


People also ask

How can integer overflows be avoided?

Avoidance. By allocating variables with data types that are large enough to contain all values that may possibly be computed and stored in them, it is always possible to avoid overflow.

What happens when int overflows Java?

If it overflows, it goes back to the minimum value and continues from there. If it underflows, it goes back to the maximum value and continues from there. If you think that this may occur more than often, then consider using a datatype or object which can store larger values, e.g. long or maybe java. math.


2 Answers

You need to use some form of BigInteger.

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

(see http://dev.clojure.org/display/doc/Documentation+for+1.3+Numerics -- evidently this auto-promotes upon overflow?)

like image 73
Steve Wang Avatar answered Sep 16 '22 17:09

Steve Wang


From Clojure 1.3, you should cast Integer(or Long) to BigInt explicitly, otherwise there will be "ArithmeticException integer overflow" error when the number is too large.

There are three solutions, please pick the one you favor:

  • use one of the auto-promoting math functions:+', -', *', /', inc', dec'

    example: (apply *' (range 1 101))

  • use the BigInt type cast function

    example: (apply * (range (bigint 1) 101))

  • change to BigInt numeric literal

    example: (apply * (range 1N 101))

Reference: Documentation for Clojure 1.3 Numerics

like image 33
dongpf Avatar answered Sep 19 '22 17:09

dongpf