public class SimplePrint {
public static void main(String[] args) {
long i = System.currentTimeMillis();
System.out.println(i);
float h = 0.0f;
i -= h;
System.out.println(i);
}
}
输出结果为:
1477904636902
1477904695296
但是当我改变了h
变量的数据类型时public class SimplePrint {
public static void main(String[] args) {
long i = System.currentTimeMillis();
System.out.println(i);
double h = 0.0f;
i -= h;
System.out.println(i);
}
}
输出已更改:
1477904677513
1477904677513
为什么会这样?
答案 0 :(得分:6)
正如JLS Sec 15.26.2中记录的那样,复合赋值运算符E1 op= E2
等同于
E1 = (T) ((E1) op (E2))
其中T是E1的类型。
所以,你在第一种情况下所做的是:
i = (long) (i - 0.0f)
为了评估-
,i
必须投放到float
,如JLS Sec 15.18.2中所述:
对操作数执行二进制数字提升(第5.6.2节)。
和5.6.2:
否则,如果任一操作数的类型为float,则另一个操作数转换为float。
问题在于i
的值无法准确表示为float
:因为float
只有24位有效数字(see here),只有值大约2 ^ 24(= 16777216)可以准确表示;但目前的毫秒时间(至少在我的机器上)大约是1477905410000,这是更大的。
因此,在转换为float时会失去精度,并且在转换回long
时无法恢复该精度。
答案 1 :(得分:5)
您的代码基本上是:
i = (long) (float) i;
或
i = (long) (double) i;
现在,在Java中,float有23位精度,而double有52位。1477904677513
有40位 - 10101100000011001111110111011101010001001
,所以当转换为float时你会丢失最后17位,所以你看到价值观发生了变化。