Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inconsistent behaviour of primitive integer types in Java

Can someone explain to me like I'm five why I get different behaviour for two of four primitive types representing integers in Java? AFAIK all four are signed and they all use the most significant bit as a sign bit, so why do byte and short behave normally, and int and long act, well, strange? The fragment of oracle docs explaining this would be perfect.

byte a = (byte) (Math.pow(2, 7)-1); //127 - as expected
short b = (short) (Math.pow(2, 15)-1); //32767 - as expected
int c = (int) (Math.pow(2, 31)-1); //2147483647 - as expected
long d = (long) (Math.pow(2, 63)-1); //9223372036854775807 - as expected

a = (byte) (Math.pow(2, 7)); //-128 - as expected
b = (short) (Math.pow(2, 15)); //-32768 - as expected
c = (int) (Math.pow(2, 31)); //2147483647 - why not '-2147483648'?
d = (long) (Math.pow(2, 63)); //9223372036854775807 - why not '-9223372036854775808'?

a = (byte) (Math.pow(2, 8)); //0 - as expected
b = (short) (Math.pow(2, 16)); //0 - as expected
c = (int) (Math.pow(2, 32)); //2147483647 - why not '0'?
d = (long) (Math.pow(2, 64)); //9223372036854775807 - why not '0'?

I'm using Oracle's Java SE 1.7 for Windows. OS is Windows 7 Professional SP1

java version "1.7.0_45"
Java(TM) SE Runtime Environment (build 1.7.0_45-b18)
Java HotSpot(TM) 64-Bit Server VM (build 24.45-b08, mixed mode)

EDIT, after reading all the answers and tuning my code.
So, to sum up, the only way I found to get expected values is the use of BigInteger. Shift operator works well for bytes, shorts and ints, but when it comes to longs, I cought it on one malfunction.

byte a = (byte) ((1l << 7) - 1); //127 - as expected
short b = (short) ((1l << 15) - 1); //32767 - as expected
int c = (int) (1l << 31) - 1; //2147483647 - as expected
long d = (1l << 63) - 1; //9223372036854775807 - as expected

a = (byte) (1l << 7); //-128 - as expected
b = (short) (1l << 15); //-32768 - as expected
c = (int) 1l << 31; //-2147483648 - as expected
d = 1l << 63; //-9223372036854775808 - as expected

a = (byte) (1l << 8); //0 - as expected
b = (short) (1l << 16); //0 - as expected
c = (int) (1l << 32); //0 - as expected
d = 1l << 64; //1 instead of 0, probably because of the word length limitation      

With BigInteger everything works flawlessly

byte a = (byte) (new BigInteger("2").pow(7).longValue() - 1); //127 - as expected
short b = (short) (new BigInteger("2").pow(15).longValue() - 1); //32767 - as expected
int c = (int) (new BigInteger("2").pow(31).longValue() - 1); //2147483647 - as expected
long d = (new BigInteger("2").pow(63).longValue() - 1); //9223372036854775807 - as expected

a = (byte) (new BigInteger("2").pow(7).longValue()); //-128 - as expected
b = (short) (new BigInteger("2").pow(15).longValue()); //-32768 - as expected
c = (int) new BigInteger("2").pow(31).longValue(); //-2147483648 - as expected
d = new BigInteger("2").pow(63).longValue(); //-9223372036854775808 - as expected

a = (byte) (new BigInteger("2").pow(8).longValue()); //0 - as expected
b = (short) (new BigInteger("2").pow(16).longValue()); //0 - as expected
c = (int) (new BigInteger("2").pow(32).longValue()); //0 - as expected
d = new BigInteger("2").pow(64).longValue(); //0 - as expected

Thanks everyone for big help!

like image 749
Moyshe Avatar asked Dec 06 '13 22:12

Moyshe


People also ask

How Java handle primitive and non Primitive data types?

Primitive types are predefined in Java. Non-primitive types are created by the programmer and is not defined by Java. Non Primitive types can be used to call methods to perform certain operations, while primitive types cannot. A primitive type always has a value, whereas non-primitive types can be null.

Which one is not primitive data type?

The string data type is a non-primitive data type but it is predefined in java, some people also call it a special ninth primitive data type. This solves the case where a char cannot store multiple characters, a string data type is used to store the sequence of characters.

Why Java still use primitive types?

Objects are much more heavyweight than primitive types, so primitive types are much more efficient than instances of wrapper classes. Primitive types are very simple: for example an int is 32 bits and takes up exactly 32 bits in memory, and can be manipulated directly.

Are Java integers primitive?

In Java, int is a primitive data type, while Integer is a Wrapper class. int , being a primitive data type has less flexibility.


3 Answers

Section 5.1.3 of the JLS talks about the behavior of the narrowing primitive conversion used by the cast

Otherwise, one of the following two cases must be true:

The value must be too small (a negative value of large magnitude or negative infinity), and the result of the first step is the smallest representable value of type int or long.

The value must be too large (a positive value of large magnitude or positive infinity), and the result of the first step is the largest representable value of type int or long.

(emphasis mine)

That is why (int) (Math.pow(2, 32)); becomes Integer.MAX_VALUE and (long) (Math.pow(2, 64)) becomes Long.MAX_VALUE.

like image 178
rgettman Avatar answered Oct 14 '22 01:10

rgettman


Math.pow() returns a double, which is then rounded on conversion to the integral types. The double is evidently rounded a hair under the precision needed to make them overflow.

like image 24
chrylis -cautiouslyoptimistic- Avatar answered Oct 14 '22 01:10

chrylis -cautiouslyoptimistic-


Instructive:

public class PowTest {
    public static void main(String[] argv) {
        double powResult = Math.pow(2.0,31.0);
        int powInt = (int) powResult;
        long powLong = (long) powResult;
        int longInt = (int) powLong;
        System.out.println("Double = " + powResult + ", int = " + powInt + ", long = " + powLong + ", longInt = " + longInt);
    }
}

Result:

C:\JavaTools>java PowTest
Double = 2.147483648E9, int = 2147483647, long = 2147483648, longInt = -2147483648

The double -> int conversion is rounded. The long -> int conversion is truncated.

like image 45
Hot Licks Avatar answered Oct 14 '22 00:10

Hot Licks