我们知道点X1和X2各自有Y1和Y2点,所以我们可以用任意X计算Y:
X - X1 Y - Y1
------- = -------
X2 - X1 Y2 - Y1
我们可以从中得到简单的公式(A):
Y = (X - X1) * (Y2 - Y1) / (X2 - X1) + Y1;
这应该在数学上等效(B):
Y = (X - X1) / (X2 - X1) * (Y2 - Y1) + Y1;
对于整数数学公式,只要乘法(X - X1) * (Y2 - Y1)
结果保持在类型范围内,A的表现就会更好。公式B不起作用,因为如果X1 <= X <= X2
,则除法总是等于0
。
对于浮点数,两者都应该有效,但我认为B会提供更好的准确性,因为乘法结果会更小。
我对浮点精度的假设是否正确?
我是否有一些我没有考虑的浮点怪癖?
假设IEEE 754浮点表示。
注1:我对浮点情况感兴趣,整数数学非常简单。
注2:FP公式的变量可能具有非整数值,但NaN和Infs不在问题范围内。
答案 0 :(得分:3)
为Y
X - X1 Y - Y1
------- = -------
X2 - X1 Y2 - Y1
(A)和(B)都表现出相似性:
(A) Y = (X - offsetX) * deltaY / deltaX + offsetY;
(B) Y = (X - offsetX) / deltaX * deltaY + offsetY;
如果点是原始整数,“B ...乘法结果将保持较小。”可能会持有,但是明智的|deltaX|
|deltaY|
可能都小于1,然后这个假设可能会失败。
要提高准确度,请考虑减去2个数字的效果(或添加2个符号不同的相似数字)。代码可以通过反转point1和point2的角色来选择X1,Y1
或X2,Y2
作为偏移量。 选择最接近X,Y的偏移量将提高准确度。
使用FP数学,*
和/
强调FP编号允许的指数范围:产品的精度可以在数学上正确的答案范围内,但范围可能溢出。
+
和-
强调精度:范围很少是一个问题,但用于形成总和的有效数字可能会有很大的取消。
如果所有坐标值最初都是整数,建议使用2x宽整数数学并得出最佳答案。
如果要对最终结果进行整数化,则保险代码使用iy = (int) round(Y);
答案 1 :(得分:2)
假设没有发生下溢或溢出,它们在准确性方面应该大致相同:乘法和除法都会产生相同的相对误差,并且由于误差大致是乘法的,因此执行操作的顺序赢了&#39 ; t会有很大的不同。
如果你对所涉及的术语的相对大小有所了解,你可能可以重新排列术语,使得减法是精确的,这可能会略微减少误差。
答案 2 :(得分:1)
通常,乘法和除法很少会导致精度的显着下降。因为这些是浮点数字,对于比例和有效数字具有单独的字段,所以获得大的中间结果本身并不是问题。 2e100/3e100
和2/3
(出于所有意图和目的)同样准确。
另一方面,加法或减法的结果比操作数小得多,这是导致精度损失的常见原因。
考虑到这一点,这两种形式基本相同。如果你的号码是主流的话。 (即乘法不会引起上溢/下溢),那么你不会遇到任何形式的任何问题。如果你不能假设你的数字是主流,那么你必须采取各种特殊预防措施才能获得好结果。
现在,我建议在(A)和(C)之间选择,而不是考虑两种形式(A)和(B):
Y = (X - X1) * (Y2 - Y1) / (X2 - X1) + Y1; (A)
Y = (X - X2) * (Y2 - Y1) / (X2 - X1) + Y2; (C)
并选择第一个因素X - X1
或X - X2
的数量较小的表单。这样,如果Y
变小,则可以最大限度地减少精度损失。
例如,让我们使用
(X1,Y1) = (-100, -100)
(X2,Y2) = (0, 0)
X = 0.76
具有三位精度。然后我们得到(A):
Y = (0.76 - -100) * (0 - -100) / (0 - -100) + -100
= 101 * 100 / 100 - 100
= 1
而对于(C),我们得到:
Y = (0.76 - 0) * (0 - -100) / (0 - -100) + 0
= 0.76 * 100 / 100 + 0
= 0.76
所以,你问题的快速答案是:
中间结果的大小本身并不重要。优先选择(B)而不是(A)。
始终认为加法和减法更可能是精度损失的原因。