关于java:当l(long) – = f(float)时发生了什么?

what is happening when l(long) -= f(float)?

本问题已经有最佳答案,请猛点这里访问。
1
2
3
4
5
6
7
8
9
10
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的数据类型时

1
2
3
4
5
6
7
8
9
10
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号

这是为什么????


如JLS第15.26.2节所述,化合物分配运算符E1 op= E2相当于

1
E1 = (T) ((E1) op (E2))

其中t是e1的类型。

所以,在第一个案例中,你要做的是:

1
i = (long) (i - 0.0f)

为了评估-,必须将i铸造到float,如JLS第15.18.2节所述:

Binary numeric promotion is performed on the operands (§5.6.2).

和5.6.2:

Otherwise, if either operand is of type float, the other is converted to float.

问题是,i的值不能精确地表示为float:因为float只有24位有效位(见此处),所以只有2^24(=16777216)左右的值才能精确地表示;但当前毫秒时间(至少在我的机器上)大约是147705410000,这要大得多。

因此,在转换为float时会丢失精度,而当转换回long时,无法恢复该精度。


您的代码基本上是:

1
i = (long) (float) i;

1
i = (long) (double) i;

现在,在Java中,浮点具有23位精度,而双精度为52位。1477904677513中有40位-10101100000011001111110111011101010001001,因此当转换为浮点时,会丢失最下面的17位,因此可以看到值的变化。