2

以下代码为 startTime 输出错误值是否令人惊讶?

public class Temp {
    public static void main(String args[]){
       float duration = (float) 2.0;
       long endTime = 1353728995;
       long startTime = 0;
       startTime = (long) (endTime - duration);
       System.out.println(startTime);
}
}
4

4 回答 4

4

它不会输出错误的值。它只是输出一个您不期望的值。

重要的是这里发生了什么:

endTime - duration

实际上被评估为:

(float) endTime - duration;

这就是数据丢失的地方。最接近float1353728995 的值是 1353729024,最接近float减 2 的结果仍然是1353729024。

这一切都遵循语言规范。JLS 第 15.8.2 节(加法运算符)指出二进制数字提升应用于操作数。

第 5.6.2 节(二进制数字提升)是这样开始的:

当运算符将二进制数值提升应用于一对操作数时,每个操作数都必须表示一个可转换为数值类型的值,以下规则按顺序适用:

  • 如果任何操作数属于引用类型,则将对其进行拆箱转换(第 5.1.8 节)。

  • 加宽原语转换(第 5.1.2 节)适用于转换以下规则指定的一个或两个操作数:

    • 如果任一操作数是 double 类型,则另一个操作数将转换为 double。

    • 否则,如果任一操作数的类型为float,则将另一个转换为float

    • ...

因此,按照这些规则,将 的longendTime转换为float,然后在float算术中执行减法。

请记住,afloat仅提供 7 个有效数字的准确度,我希望其余的都相当明显。

请注意,如果没有将结果转换为long,编译器会更清楚地说明发生了什么:

Test.java:8: error: possible loss of precision
    long startTime = endTime - duration;
                             ^
  required: long
  found:    float
1 error

这清楚地表明,结果将是 a float,这应该对操作将如何执行以及预期的准确性提出警告。

于 2012-11-28T19:24:37.377 回答
0

如果您希望结果为 long,则将浮点转换为 long。

 float duration = (float) 2.0;
    long endTime = 1353728995;
    long startTime = 0;
    startTime = endTime - (long)duration;
    System.out.println(startTime);

输出:

1353728993

如果您不强制转换,它将被视为浮点值,结果将出乎意料。

于 2012-11-28T19:22:02.040 回答
0

这都是因为浮点表示法。

当您使用float至少一个参数执行任何操作时,所有参与的数字都将提升为float。在这里,您将在减法之前endTime转换为浮点数,因为这使用了指数表示。这种表示不是很精确,因此您会看到不同的结果。1.35372902E9IEEE 754 notation

好像你在哪里

    startTime =  (endTime - (long)duration);

然后它的操作使用 long ,你应该得到预期的结果。

于 2012-11-28T19:26:04.057 回答
0

double并且float经常损失精度。这可能就是您在这里看到的。

请注意,您实际上是在计算:

startTime = (long) ((float)endTime - duration);

因为编译器会自动将 long 转换为 float 以进行减法。这是有据可查的,一些好的代码检查器实际上会警告你这一点。

你可能想要的是这样的:

startTime = endTime - (long)duration;

但是你应该这么说。

你也可以通过使用得到正确的

startTime = (long) (endTime - (double)duration);

但这也不安全

于 2012-11-28T19:26:48.610 回答