我正在运行代码,试图找出由于在整数十进制数字类型之间进行转换而导致精度丢失时Java的行为,并且我发现了一个意外的结果:
long l2 = 999999999999999999L; //outside of range -2147483648..2147483647 for int
int i3=(int)l2;
System.out.println(l2); //999999999999999999, as expected.
System.out.println(i3); //I expected 2147483647, but got -1486618625
有人可以解释我是如何从一个大的正长线中得到一个大的负数吗?我本来期望系统至少做出尽力而为的投射尝试,返回最大正整数(最接近的有效int到long,它太大而不能存储在整数中。)相反,我得到了一个负数对我来说没有意义的数字。
答案 0 :(得分:2)
long
到int
的缩小基元转换会丢弃除原始数字的低32位之外的所有内容,因此您无法获得Integer.MAX_VALUE
。
有符号整数到整数类型T的缩小转换只会丢弃除n个最低位之外的所有位,其中n是用于表示类型T的位数。除了可能丢失有关幅度的信息之外数值,这可能导致结果值的符号与输入值的符号不同。
这与从浮点类型到int
的原始缩小转换形成对比,如果原始值太大,则可能导致Integer.MAX_VALUE
。
double l2 = 999999999999999999.0;
System.out.println((int) l2);
打印:
2147483647
答案 1 :(得分:0)
让我们先来看看结果编号位:
现在看一下999999999999999999的位表示:
请注意,前两种情况都是相同的。
现在考虑JLS,第5.1.3节,如rgettman所述:
有符号整数到整数类型T的缩小转换只会丢弃除n个最低位之外的所有位,其中n是用于表示类型T的位数。除了可能丢失有关幅度的信息之外数值,这可能导致结果值的符号与输入值的符号不同。
因此在进行演员表时你只能保留32个第一位(10100111011000111111111111111111)。因此,考虑有符号整数的最高位代表数字的符号,你将得到负数(1)0100111011000111111111111111111
这等于-1486618625作为十进制值。
答案 2 :(得分:0)
演员不进行任何对话,也不关心数据。 (或关于截断)
二进制文件中的 999999999999999999
为0000 1101 1110 0000 1011 0110 1011 0011 1010 0111 0110 0011 1111 1111 1111 1111
。
将其转换为signed int时,只使用低32位:
1010 0111 0110 0011 1111 1111 1111 1111
- 现在,这个数字意味着(它现在由于转换而成为有符号整数):
010 0111 0110 0011 1111 1111 1111 1111
将在{... 1}}中显示...不正确。660865023
以获得实际数值:这样:
1
010 0111 0110 0011 1111 1111 1111 1111
101 1000 1001 1100 0000 0000 0000 0000 + 1
101 1000 1001 1100 0000 0000 0000 0001
是101 1000 1001 1100 0000 0000 0000 0001
- 它是否定的:瞧,你的1486618625
答案 3 :(得分:-1)
有符号整数的最高位是符号位。因此,如果您将操作溢出到该位,您将得到一个负数。在这种情况下,你是通过施放来完成的。
= 1101 1110 0000 1011 0110 1011 0011 1010 0111 0110 0011 1111 1111 1111 1111
Truncated to (int):
1010 0111 0110 0011 1111 1111 1111 1111
Twos' compliment transform:
0101 1000 1001 1100 0000 0000 0000 0001 = 1486618625