Clojure integer overflow

I am running Clojure 1.4.0. Why do I add Integer/MAX_VALUE and 1, I get Long, but if I add Integer/MAX_VALUE to myself, I get an exception?

 => (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) 

Don't they act the same? Why is adding two MAX_VALUE values ​​overflowing but adding 1 is not working?

I saw this SO question , but they change their behavior than me.

+7
source share
3 answers

What is strange, I see different results with Clojure 1.4.0 and Java (TM) SE Runtime Environment (build 1.7.0_06-b24), on Ubuntu 12.04 64bit:

 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 

You can always check the Java classes that clojure.core uses for numerical calculations to find out how the functionality is implemented:

Operator implementation + in:

 (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)) ([xy] (. clojure.lang.Numbers (add xy))) ([xy & more] (reduce1 + (+ xy) more))) 

Java implementation of adding longs:

 final public Number add(Number x, Number y){ return num(Numbers.add(x.longValue(),y.longValue())); } 

Edit: Tested with Clojure 1.2.1
I did a quick test with Clojure 1.2.1, and with this version of Clojure I get exactly your behavior.

 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) 

I would say that you ran the test with Clojure 1.2.x, not 1.4.0. What is the meaning of * clojure -version * in your REPL?

+7
source

It sounds like you have your answer, but here are a few more interesting points:

java (all versions) and clojure (> 1.3.0) default behavior is different from overflow behavior

in 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 

This is because arithmetic default wrappers on 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 has versions of some operating systems that behave like java

 (unchecked-inc Long.MAX_VALUE) => Long.MIN_VALUE 

You can do unchecked operations by default by setting *unchecked-math* to true

 (set! *unchecked-math* true) (inc Long/MAX_VALUE) => (Long.MIN_VALUE) (int (inc Integer/MAX_VALUE)) => (Integer.MIN_VALUE) of type Integer 

There are many other interesting (unchecked-*) operations.

+4
source

Starting with version 1.3.0, Clojure uses Longs for all primitive numbers. you just need to use large numbers to get overflow.

  (def max-plus-one (+ Long/MAX_VALUE one)) 
+1
source

All Articles