我正在做一些浮点计算,结果并不像我希望的那样准确。
这是算法:
... 中心 = (max_x + min_x) / 2 距离 = old_x - 中心 new_x = 中心 + (距离 * 因子) 返回 new_x
min_x、max_x 和 old_x 都是浮点数。我相信当我取最大值和最小值的平均值时会引入最大的误差,然后将误差乘以因子(可以是浮点数)。
我怎样才能最大限度地减少由于 FP 计算导致的错误,以便 new_x 尽可能精确?
我正在做一些浮点计算,结果并不像我希望的那样准确。
这是算法:
... 中心 = (max_x + min_x) / 2 距离 = old_x - 中心 new_x = 中心 + (距离 * 因子) 返回 new_x
min_x、max_x 和 old_x 都是浮点数。我相信当我取最大值和最小值的平均值时会引入最大的误差,然后将误差乘以因子(可以是浮点数)。
我怎样才能最大限度地减少由于 FP 计算导致的错误,以便 new_x 尽可能精确?
如果old_x和center很接近,那么您将失去精度。
这叫做失去意义
您可以更改计算,以便最后发生减法:
center = (max_x + min_x) / 2
new_x = (center + (old_x * factor)) - (center * factor)
根据您的语言,您可能可以使用固定/任意精度的数字类型,例如python 中的小数或Java 中的 BigDecimal。
这至少消除了原始算法中的一个错误来源:
# Adding min and max can produce a value of larger magnitude, losing some low-order bits
center = min_x + (max_x - min_x)/2
distance = old_x - center
new_x = center + (distance * factor)
return new_x
如果您对和之间的关系有更多了解old_x
,您可能会做得比这更好。min_x
max_x
正如 Yochai 所说,您的问题可能是由减法引起的old_x - center
。如果old_x
和center
彼此接近,那么您将失去精度。
简单的解决方案是使用double
而不是进行计算float
,但我想这是不可能的。在这种情况下,您需要摆脱减法。一种可能是
distance_max = max_x - center
distance_min = min_x - center
distance = (distance_max + distance_min) / 2
new_x = center + factor * distance
如果max_x
和相距甚远,而 和 的平均值min_x
接近,这会有所帮助。如果这没有帮助,也许您可以调整计算,以便您实际计算,但需要更改您没有向我们展示的部分。center
max_x
min_x
center
max_x
max_x - center
所有以前的实现都没有使用舍入,因此有很大的错误:以下是在定点数学中如何做到这一点:我使用的是 X.1u 预置(1 LSB 用于小数部分)。
//center = (max_x + min_x) / 2
center = max_x + min_x // zero error here
// distance = old_x - center
distance = (old_x << 1) - center // zero error here
//new_x = center + (distance * factor)
new_x = (**1** + center + (distance * factor)) >> 1
return new_x
如果 factor 也是一个固定点(整数),其中 N 位描述分数,则 new_x 可以计算为:
new_x = ( (1 << N) + (center << N) + (distance * factor) ) >> (N + 1)
了解了各个部分之后,就可以将上面的这行代码进行compact了:
new_x = ( ((1 + center) << N) + (distance * factor) ) >> (N + 1)
当然,使用的整数类型应该足够大。如果有效范围未知,则应检查此函数的输入和其他内容。在大多数情况下,这不是必需的。
这和它在定点数学中的表现一样好。这就是硬件电路执行整数数学运算的方式。