为什么在案例2中对于相同的值有两个不同的答案:在Java 7上?

时间:2017-01-18 12:57:08

标签: java bit-manipulation type-conversion

为什么在案例2中对于相同的值有两个不同的答案:在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);
  }
}

以下是Ideone的答案。

Case 1:
size :549755813888
size :549755813888 
Case 2:
size :2199023255552
size :0

2 个答案:

答案 0 :(得分:4)

你看到零的原因是因为它是一个整数溢出。在这种情况下,您会触发JLS Multiplication Operator,它指出低端位将是溢出的结果。

例如

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

将打印出来

-2147483648 // Integer overflow
10000000000000000000000000000000 // Integer overflow

在你的情况下

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

它会打印出来

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

那么究竟发生的是你的计算以一个整数开始

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

如果你没有声明它很长,它就不会这样处理它。 要解决此问题,您必须在第一个操作数处使用大写L或小写l

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

结果是

2199023255552 // long value
100000000000000000000000000000000000000000

答案 1 :(得分:2)

案例1

1024是int。因此,在int算术中执行1024 * 1024 * 1024,即32位。由于1024是2 ^ 10,1024 * 1024 * 1024是2 ^ 30,因此它适合32位int。接下来,你乘以512L,即long(请使用大写L;它很容易误读数字1的小l)。因此,2 ^ 30转换为long,并且两个long值相乘。结果是2 ^ 39,它适合long(不适合int)。一切都很好。

案例2

1024 * 1024 * 1024与之前一样是2 ^ 30,与以前一样是int。接下来的1024也在int,所以下一个乘法是在32位算术中完成并且溢出,因为结果将是2 ^ 40,这是不适合的。因为数字以32个零结束,结果现在转换为long(0L),因此它可以乘以2L。 0 * 2为0(无论是32位还是64位)。

<强>修正

如前所述,只要在溢出发生之前执行此操作,技术上就足以将其中一个常量标记为long(使用L)。 1024 * 1024 * 1024 * 1024L * 21024L * 1024 * 1024 * 1024 * 2应该有效。不过,我更喜欢1024L * 1024L * 1024L * 1024L * 2L。我发现阅读和理解更容易。我觉得不错的其他选项包括1L << 410x200_0000_0000