我试图找出一些非常奇怪的Java行为 . 我有一个涉及double的公式,但是“保证”给出一个整数答案 - 具体来说,是一个无符号的32位整数(唉,Java不能很好) . 不幸的是,我的答案有时不正确 .
最终我发现了这个问题,但对我来说这个行为仍然很奇怪:一个 double
直接转换为 int
似乎被限制在 MAX_INT
为有符号整数,而 double
转换为 long
然后被转换为 int
给出了预期的答案(-1;无符号32位整数的MAX INT,表示为带符号的32位整数) .
我写了一个小测试程序:
public static void main(String[] args) {
// This is the Max Int for a 32-bit unsigned integer
double maxUIntAsDouble = 4294967295.00;
long maxUintFromDoubleAsLong = (long)maxUIntAsDouble;
long maxUintFromDoubleAsInt = (int)maxUIntAsDouble;
int formulaTest = (int) (maxUintFromDoubleAsLong * 1.0);
int testFormulaeWithDoubleCast = (int)((long) (maxUintFromDoubleAsLong * 1.0));
// This is a more-or-less random "big number"
long longUnderTest = 4123456789L;
// Max int for a 32-bit unsigned integer
long longUnderTest2 = 4294967295L;
int intFromLong = (int) longUnderTest;
int intFromLong2 = (int) longUnderTest2;
System.out.println("Long is: " + longUnderTest);
System.out.println("Translated to Int is:" + intFromLong);
System.out.println("Long 2 is: " + longUnderTest2);
System.out.println("Translated to Int is:" + intFromLong2);
System.out.println("Max UInt as Double: " + maxUIntAsDouble);
System.out.println("Max UInt from Double to Long: " + maxUintFromDoubleAsLong);
System.out.println("Max UInt from Double to Int: " + maxUintFromDoubleAsInt);
System.out.println("Formula test: " + formulaTest);
System.out.println("Formula Test with Double Cast: " + testFormulaeWithDoubleCast);
}
当我运行这个小程序时,我得到:
Long is: 4123456789
Translated to Int is:-171510507
Long 2 is: 4294967295
Translated to Int is:-1
Max UInt as Double: 4.294967295E9
Max UInt from Double to Long: 4294967295
Max UInt from Double to Int: 2147483647
// MAX INT for an unsigned int
Formula test: 2147483647
// Binary: all 1s, which is what I expected
Formula Test with Double Cast: -1
最下面的两行是我想要了解的 . 双重演员给了我预期的“-1”;但直接转换为MAX_INT提供了一个32位有符号整数 . 来自C背景,我会理解它是否给了我一个“奇数”而不是预期的-1(又名“天真铸造”),但这让我感到困惑 .
那么,对于那个问题:这是Java中的"expected"行为(例如,任何 double
直接转换为 int
将"capped"到 MAX_INT
)?对任何意外类型进行强制转换吗?我希望它与 short
和 byte
类似,例如;但什么是'expected behavior'什么时候铸造超大双倍浮动?
谢谢!
2 回答
这是预期的行为 . 请记住,Java中没有原始的unsigned long或int类型,并且Java Language Specification(Java 7)for narrowrowing primitive conversion(5.1.3)声明将"too small or too large"浮点值(可以是double或float)转换为整数类型int或long将使用有符号整数类型的最小值或最大值(强调我的):
第一种情况
int formulaTest = (int) (maxUintFromDoubleAsLong * 1.0);
因此通过乘法将maxUintFromDoubleAsLong
提升为double,然后将其转换为int . 由于该值太大而无法表示为有符号整数,因此该值变为2147483647(Integer.MAX_VALUE)或0x7FFFFFFF .至于后一种情况:
所以
int testFormulaeWithDoubleCast = (int)((long) (maxUintFromDoubleAsLong * 1.0));
首先将maxUintFromDoubleAsLong提升为double,返回long(仍然适合)然后再提升为int . 在最后一次转换中,多余的位被简单地删除,留下0xFFFFFFFF,当被解释为有符号整数时为-1 .这就是语言规范的编写方式 . 将浮点数转换为整数类型,如果该值对于目标而言太大,则替换最大值 . 在从一个整数类型到较小整数类型的缩小转换中,丢弃高位比特 .
见JLS 5.1.3. Narrowing Primitive Conversion
所以, Headers 中问题的答案是“是” .