我正在尝试使用一些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时,