Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why two different answers are coming for the same value in case 2: on Java 7?

Why two different answers are coming for the same value in case 2: on Java 7?

class Ideone
{
  public static void main (String[] args) throws java.lang.Exception
  {
    System.out.println("Case 1:"); 
    long size=(long)1<<39;
    System.out.println("size :"+size); 
    size=1024*1024*1024*512l;
    System.out.println("size :"+size);  
    System.out.println("Case 2:"); 
    size=(long)1<<41;
    System.out.println("size :"+size); 
    size=1024*1024*1024*1024*2l;
    System.out.println("size :"+size);
  }
}

Answers are given below from Ideone.

Case 1:
size :549755813888
size :549755813888 
Case 2:
size :2199023255552
size :0
like image 639
Mohd Altaf Avatar asked Dec 19 '25 06:12

Mohd Altaf


2 Answers

The reason why you are seeing zero is because it's a Integer overflow. In this exact scenario you trigger the JLS Multiplication Operator which states that the lower end bits will be the result of a overflow.

For example

System.out.println((1025*1024*1024*1024*2));
System.out.println(Integer.toBinaryString(1025*1024*1024*1024*2));

Will print out

-2147483648 // Integer overflow
10000000000000000000000000000000 // Integer overflow

In your case

System.out.println((1024*1024*1024*1024*2)); 
System.out.println(Integer.toBinaryString(1024*1024*1024*1024*2));

It will print out

0 // still a overflow, but the lower ordered bits are 0, since we dont see trailing zero bits
0

So what exactly happens is that you calculation starts off with an Integer

size=1024*1024*1024*1024*2l;

If you don't state that it's a long, it will not handle it as such. To fix it you have to use uppercase L or lowercase l at the first operand.

 size=1024L*1024*1024*1024*2l;

    System.out.println((1024L*1024*1024*1024*2l));
    System.out.println(Integer.toBinaryString(1024L*1024*1024*1024*2l)); // will not work, because the compiler knows it's a long
    System.out.println(Long.toBinaryString(1024L*1024*1024*1024*2l));

The result is

2199023255552 // long value
100000000000000000000000000000000000000000
like image 55
Murat Karagöz Avatar answered Dec 21 '25 20:12

Murat Karagöz


Case 1

1024 is an int. So 1024 * 1024 * 1024 is performed in int arithmetic, that is, in 32 bits. Since 1024 is 2^10, 1024 * 1024 * 1024 is 2^30, so it fits in a 32-bit int. Next you multiply by 512L, that is, a long (please use capital L; it’s so easy to misread a small l for digit 1). Therefore, 2^30 is converted to long and the two long values are multiplied. Result is 2^39, which fits in a long (would not have fit in an int). All is fine.

Case 2

1024 * 1024 * 1024 is 2^30 as before, and is an int as before. The next 1024 is in int too, so the next multiplication is done in 32-bit arithmetic and overflows because the result would have been 2^40, which cannot fit in. Since the number ends in 32 zeros, the result is 0. This is now converted to long (0L) so it can be multiplied by 2L. 0 * 2 is 0 (no matter if you do it in 32 or 64 bits).

Fix

As has been said, it’s technically enough to mark one of the constants as long (with the L), as long as you do it before the overflow happens. 1024 * 1024 * 1024 * 1024L * 2 or 1024L * 1024 * 1024 * 1024 * 2 should work. I do, however, prefer 1024L * 1024L * 1024L * 1024L * 2L. I find it easier to read and understand. Other options I find nice include 1L << 41 and 0x200_0000_0000.

like image 42
Ole V.V. Avatar answered Dec 21 '25 20:12

Ole V.V.