为什么在Java 7中针对同一个值在情况2中会得到两个不同的答案?

3

为什么在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

4
将其改为 1024L*1024L*1024L*1024L*2L,看看会发生什么。 - RealSkeptic
1
@RealSkeptic 只有第一个操作数需要是双精度字面量,对吗? - Andrew Li
我同意你的观点,但是为什么情况1能够工作呢?即 size=102410241024*512l; System.out.println("size :"+size); 它给出的结果超过了(2^31) - 1。 - Mohd Altaf
@JornVernee 不,再检查一遍,它是102410241024*512,超出了int的范围。 - Mohd Altaf
@MohdAltaf 是的,但 512 是一个 long 文字。你只需使用一个大的 int * 512L,然后将其保留为 long - Jorn Vernee
显示剩余3条评论
2个回答

5
你看到0的原因是因为这是整数溢出。在这种情况下,你触发了JLS乘法运算符,它规定低位比特将成为溢出的结果。
例如:
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

我同意溢出是在第二种情况下。但这就是为什么我也提到了第一种情况,其中也存在溢出,但在这种情况下,溢出会自动处理,无需进行任何转换。 - Mohd Altaf
@MohdAltaf 没有溢出。1024*1024*1024是一个有效的整数值,你将其乘以一个长整型值512l,因此结果是一个长整型值。然而,如果使用1024*1024*1024*1024*512l会导致整型溢出。 - Murat Karagöz
@MohdAltaf 如果这个答案能够满足您的需求,您也可以接受它。 - Murat Karagöz

2

案例1

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

案例2

1024 * 1024 * 1024与之前一样是2 ^ 30,并且与之前一样是int。下一个1024也是int,因此下一个乘法在32位算术中完成并溢出,因为结果将是2 ^ 40,无法容纳。由于数字以32个零结尾,结果为0。现在将其转换为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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接