【问题标题】:Why two different answers are coming for the same value in case 2: on Java 7?为什么在案例 2:在 Java 7 上对于相同的值会有两个不同的答案?
【发布时间】:2017-06-02 20:50:32
【问题描述】:

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

【问题讨论】:

  • 改成1024L*1024L*1024L*1024L*2L看看会发生什么。
  • (long)1024*1024*1024*1024*2,它们将是相同的
  • @RealSkeptic 只有第一个操作数需要是双字面量,对吧?
  • @AndrewLi 是的,但是如果你使用的是 long,你最好养成使用 long 字面量的习惯。
  • 我同意你的观点,但是为什么案例 1 有效?即尺寸=1024*1024*1024*512l; System.out.println("尺寸:"+尺寸); .它给出的结果大于 (2^31) - 1。

标签: java bit-manipulation type-conversion


【解决方案1】:

您看到零的原因是因为它是整数溢出。在这个确切的场景中,您触发了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

【讨论】:

  • 我同意在 case 2 中溢出。但这就是为什么我还提到了案例 1,其中也存在溢出,但在这种情况下,溢出会自动处理,无需任何转换。
  • @MohdAltaf 没有溢出。 1024*1024*1024 是一个有效的 Integer 值,你将它与 512l 相乘,这是一个 long 值。因此结果是一个长值。另一方面,1024*1024*1024*1024*512l 会溢出一个整数。
  • @MohdAltaf 如果这个答案让你满意,你不妨接受它。
【解决方案2】:

案例 1

1024 是一个int。所以1024 * 1024 * 1024是在int算术中进行的,也就是32位。由于 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 &lt;&lt; 410x200_0000_0000

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-24
    相关资源
    最近更新 更多