当你需要使用浮点数时,如何避免浮点数错误



我正在尝试使用一些UI按钮将位置移动0.1或-0.1来影响3D模型的翻译。

我的模型位置是一个三维浮点数,所以简单地将0.1f添加到其中一个值会导致明显的舍入误差。虽然我可以使用BigDecimal之类的东西来保持精度,但我仍然需要在最后将其从浮点数转换回浮点数,并且它总是导致愚蠢的数字,使我的UI看起来一团糟。

我可以调整显示的值,但随着编辑的增加,舍入误差只会变得更糟,而且它们使我的保存文件很难阅读。

那么,当我需要使用浮点数时,我如何避免这些错误呢?

Kahan求和和两两求和算法有助于减少浮点误差。下面是一些用于Kahan算法的Java代码。

我将使用Rational类。有很多,这个看起来应该可以工作。

一个显著的代价是将Rational转化为float,另一个显著的代价是将分母转化为gcd。我贴出来的这个让分子和分母一直处于完全约简状态,如果你总是加或减1/10,这应该是相当有效的。

此实现保留规范化(即具有一致的符号)但未减少的值。

一个简单的解决方案是使用固定精度。例如,一个你想要的10倍或100倍的整数。

float f = 10;
f += 0.1f;

int i = 100;
i += 1;  // use an many times as you like
// use i / 10.0 as required.

在任何情况下我都不会使用float,因为你会得到比double更多的舍入误差,几乎没有任何好处(除非你有数百万的浮点值)double给你多8位精度,并且合理的舍入将不会看到这些错误。

如果你坚持使用float:避免此错误的最简单方法是使用精确的浮点数,但是在所需值

附近

round(2^n * value) * 1/2^n.

n是位的数目,值要使用的数目(在您的例子中是0.1)

在你的情况下,增加精度:

n = 4 => 0.125
N = 8 (byte) => 0.9765625
N = 16(短)=> 0.100006103516....

长数字链是二进制转换的产物,实数的位数要少得多。

因为浮点数是精确的,所以加法和减法也是精确的不会引入偏移误差,但总是会只要比特数是可预测的

如果您担心您的显示会受到损害使用这个解决方案(因为它们是奇数浮点数),使用并且只存储整数(step increase -1/1)。内部设置的最终值是

x = value * step.

当步长增加或减少1时,

最新更新