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!