为什么下面的代码打印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);
我是Integer类型。如果第二个代码示例(添加两个整数)如果结果超出正范围可以包装到负侧,为什么第一个样本不能包装? 另外,
i = 2147483648 +1 ;
System.out.println(i);
这与第二个代码示例非常相似会抛出编译错误,说第一个文字超出整数范围? 我的问题是,根据第二个代码示例,为什么第一个和第三个样本不能自动换行到另一个?
答案 0 :(得分:12)
对于第一个代码示例,结果从double
缩小为int
。 JLS 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。
答案 1 :(得分:4)
那为什么像这样的代码自动换向负面并打印-2147483648?
这称为溢出。 Java是这样做的,因为C做到了。 C这样做是因为大多数处理器都这样做。在某些语言中,这不会发生。例如,某些语言会抛出异常,而在其他语言中,类型将变为可以保存结果的东西。
我的问题是,根据第二个代码示例,为什么第一个和第三个样本不能自动换行到另一个?
关于第一个程序:Math.pow返回一个double并且不会溢出。当double被转换为整数时,它会被截断。
关于您的第三个程序:溢出很少是理想的属性,通常表明您的程序不再有效。如果编译器只是通过评估一个几乎肯定是代码中的错误的常量就可以看到它出现溢出。如果你想要一个大的负数,你为什么要写一个大的正数呢?