在铸造浮动之前尽可能长时间使用双倍?

时间:2016-07-09 22:38:14

标签: java floating-point precision

我有一个矢量类(2D数学矢量),其中float为其组成部分。

对于某些中间计算,我可以选择使用双打。我应该尽可能长时间地使用中间双精度,只能在最后进行浮动,或者最好尽快将任何双精度投射到浮子上吗?

例如,以下是矢量标准化的两种可能实现方式。

首先,保持所有计算的加倍:

public class Vector2f {    

    private float x;
    private float y;

    ....

    public Vector2f normalize() {
        double length = Math.sqrt((x * x) + (y * y));
        return new Vector2f(
                (float) (x / length),
                (float) (y / length)
        );
    }
}

其次,立即转换为浮动:

public Vector2f normalize() {
    float length = (float) Math.sqrt((x * x) + (y * y));
    return new Vector2f(
            x / length,
            y / length
    );
}

2 个答案:

答案 0 :(得分:4)

一般来说,尽可能长时间保持精度总是更好,特别是如果你的值非常小/接近于零。

尝试以下几行:

System.out.println(0.00001f * 0.00002f / 0.00000003f);
System.out.println(0.00001d * 0.00002d / 0.00000003d);

输出将是:

0.0066666664
0.006666666666666668

哪一个更好,你怎么看?因此,这些错误可能会累积在您的计算中并影响您的输出。

让它更有趣:

System.out.println(0.00001f * 0.00002f * 0.00000003f* 0.00000003f* 0.00000003f* 0.00000003f* 0.00000003f * 0.00000003f / 0.00000003f / 0.00000003f / 0.00000003f / 0.00000003f/ 0.00000003f/ 0.00000003f);
System.out.println(0.00001d * 0.00002d * 0.00000003d* 0.00000003d* 0.00000003d* 0.00000003d* 0.00000003d * 0.00000003d / 0.00000003d / 0.00000003d / 0.00000003d / 0.00000003d/ 0.00000003d/ 0.00000003d);

并输出:

0.0
2.0000000000000003E-10

注意小值!

答案 1 :(得分:0)

最终从double转换为float的结果将比在这些操作之前转换的结果更准确。

         x / length,
         y / length

解决方案似乎比其他解决方案更好。