l(长) - = f(浮动)时发生了什么?

时间:2016-10-31 09:06:28

标签: java type-conversion

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

为什么会这样?

2 个答案:

答案 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位,所以你看到价值观发生了变化。