【问题标题】:Basic question on Java's int关于 Java 的 int 的基本问题
【发布时间】:2011-03-29 19:45:27
【问题描述】:

为什么下面的代码会打印 2147483647,实际值是 2147483648?

    i = (int)Math.pow(2,31) ;
    System.out.println(i);

我知道 int 可以容纳的最大正值是 2147483647。那么为什么像这样的代码会自动换行到负端并打印 -2147483648?

i = (int)Math.pow(2,31) +1 ;
System.out.println(i);

i 是整数类型。如果第二个代码示例(两个整数相加)在结果超出正数范围时可以换行到负数,为什么第一个示例不能换行? 还有,

i = 2147483648 +1 ;
System.out.println(i);

与第二个代码示例非常相似会引发编译错误,说第一个文字超出整数范围? 我的问题是,根据第二个代码示例,为什么第一个和第三个示例不能自动换行?

【问题讨论】:

  • 为了澄清,这与java.lang.Integer无关,与int不同。
  • 这有什么关系?即使我将其转换为 (Integer) 而不是 int,问题(或问题)也将是相同的。

标签: java


【解决方案1】:

对于第一个代码示例,结果从double 缩小到intJLS 5.1.3 描述了如何缩小从双精度到整数的转换。

相关部分是:

该值必须太大(a 大幅度的正值或 正无穷大),结果 第一步是最大的 int 类型的可表示值或 长。

这就是为什么 2^31 (2147483648) 减少到 Integer.MAX_VALUE (2147483647)。

i = (int)(Math.pow(2,31)+100.0) ;  // addition note the parentheses

i = (int)10000000000.0d;   // == 2147483647

当加法是在没有括号的情况下完成时,就像在你的第二个例子中一样,我们然后处理整数加法。整数类型使用2's complement 来表示值。在这个方案下加 1 到

 0x7FFFFFFF   (2147483647)

给予

 0x80000000

这是 -2147483648 的 2 补码。一些语言对算术运算执行溢出检查(例如,Ada 会抛出异常)。 Java,它的 C 遗产不检查溢出。当算术运算上溢或下溢时,CPU 通常会设置overflow flag。语言运行时可以检查这个标志,尽管这会带来额外的开销,有些人觉得这是不必要的。

第三个示例无法编译,因为编译器会根据其类型范围检查字面值,并为超出范围的值给出编译器错误。见JLS 3.10.1 - Integer Literals

【讨论】:

  • 不是2147483647 = 0x7FFFFFFF-2147483648 = 0x80000000吗?
  • @ILMTitan - 这是正确的,这就是我认为我写的,但我看到我写了别的东西。现在已更正。
【解决方案2】:

那么为什么像这样的代码会自动换行并打印-2147483648?

这称为溢出。 Java 做到了,因为 C 做到了。 C 这样做是因为大多数处理器都这样做。在某些语言中,这不会发生。例如,某些语言会抛出异常,而在其他语言中,类型会更改为可以保存结果的类型。

我的问题是,根据第二个代码示例,为什么第一个和第三个示例不能自动换行?

关于第一个程序:Math.pow 返回一个双精度并且不会溢出。当 double 转换为整数时,它会被截断。

关于您的第三个程序:溢出很少是一个理想的属性,并且通常表明您的程序不再工作。如果编译器仅仅通过评估一个几乎可以肯定的常量就可以看到它发生了溢出,这就是代码中的错误。如果您想要一个大的负数,为什么要写一个大的正数?

【讨论】:

    猜你喜欢
    • 2011-11-26
    • 2011-11-26
    • 1970-01-01
    • 2013-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多