我试图用Java实现游戏的基本2D矢量数学函数。它们将被游戏密集使用,所以我希望它们尽可能快。
我从整数开始作为矢量坐标,因为游戏对坐标不需要更精确,但对于所有计算,我仍然需要更改为双向量以获得清晰的结果(例如,两条线之间的交点)。 / p>
使用双打,有舍入错误。我可以简单地忽略它们并使用像
这样的东西d1 - d2 <= 0.0001
比较值,但我假设进一步的计算误差可以总结,直到它变得重要。所以我认为我可以在每次可能不准确的操作之后绕过它们,但结果会产生更糟糕的结果,因为该程序还会舍入不确定的值(例如0.33333333...
- &gt; 0.3333300...
)。 / p>
使用BigDecimal会太慢。
解决此问题的最佳方法是什么?
答案 0 :(得分:5)
当您使用需要精确计算的数字时,您需要确保您没有做类似的事情:(这就像您目前所做的那样)
随着过程的继续,这将导致舍入错误的累积;长期为您提供极为无懈可击的数据。在上面的示例中,实际上,您每次开始float
4 时都会四舍五入,每次变得越来越不准确!
这将有助于避免累积误差的累积,因为每次计算仅基于 1 转换,并且该转换的结果不会复合到下一次计算中。
最佳攻击方法 将以最高精度开始,然后根据需要进行转换,但保持原始完整。我建议你按照我发布的第二张照片进行操作。
我从整数开始作为矢量坐标,因为游戏对坐标不需要更精确,但对于所有计算,我仍然需要更改为双向量以获得清晰的结果(例如,两条线之间的交点)。 / p>
重要的是要注意,如果对最终结果没有明显影响,则不应尝试对值进行任何类型的舍入;你只会做很少甚至没有收获的工作,如果做得足够经常会有性能下降。
答案 1 :(得分:2)
这是prior answer的一个小小的补充。将float转换为整数时,重要的是舍入而不仅仅是转换。在以下程序中,d
是最大的双精度,严格小于1.0。它可能很容易因计算结果而产生,该结果将在无限精确的实数运算中得到1.0。
简单转换获得结果0.舍入优先获得结果1.
public class Test {
public static void main(String[] args) {
double d = Math.nextDown(1.0);
System.out.println(d);
System.out.println((int)d);
System.out.println((int)Math.round(d));
}
}
输出:
0.9999999999999999
0
1