bitops
bitops

Reputation: 4292

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

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?

Upvotes: 24

Views: 10574

Answers (6)

NielsK
NielsK

Reputation: 6956

Ruby has auto-promoting calculations, changing to a bigger bittype number when the result overflows its type. Because of performance considerations, calculations from Clojure 1.3 up will not be auto-promoting, and you need to take into account if a calculation can overflow, or use one of the auto-promoting math functions (+', -', *', /') if performance wouldn't be an issue.

Upvotes: 6

dongpf
dongpf

Reputation: 1597

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

Upvotes: 8

cskksc
cskksc

Reputation: 68

Stumbled onto the same situation. For me using "1.0" instead of "1" did the trick.

(apply * (range 1.0 1000))

As documented, there is a difference between floats and decimals.

Upvotes: 1

BLUEPIXY
BLUEPIXY

Reputation: 40145

in 1.3.0

(apply * (range 1N 101N));clojure.lang.BigInt

(apply * (range 1M 101M));java.math.BigDecimal

Upvotes: 1

Andrew Cooper
Andrew Cooper

Reputation: 32576

I don't know Clojure, but it looks like it's using 32-bit or 64-bit integers to do the calculation. 32-bit signed integers have a maximum value of 2^31 - 1 (a bit over 2*10^9). 64-bit integers have a max value of 2^64 - 1 (a bit over 4*10^18). The value you got from Ruby is much higher than that.

Obviously Ruby is using some other number representation under the hood.

Upvotes: 0

Steve Wang
Steve Wang

Reputation: 1824

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?)

Upvotes: 43

Related Questions