使用距离平方检查而不是距离有什么缺点吗?


29

我使用了距离平方检查来进行我的所有距离(vector3长度)检查,这是由于不产生平方根会提高性能(就像在普通长度检查中一样)。

从外观上看,平方距离检查在每种情况下都能正常工作:

if x^2 < y^2, then x < y, even when 0 < (x or y) < 1

我不考虑x或y小于0的情况,因为距离和距离平方始终为正。

由于此方法有效,因此似乎从未需要进行距离检查,但是我a不安,感觉自己缺少某些东西。在对精度要求严格的情况下,这种方法是否仍然有效?

Answers:


41

使用平方长度比较距离时,我没有发现任何缺点。这样思考:您只是跳过了sqrt,不会给您带来任何额外的准确性。如果您不需要实际的欧几里德距离,则可以放心sqrt

当然,平方长度的比例尺与欧几里得距离完全不同,因此对于诸如寻路启发式算法之类的东西而言,它是不好的选择


16
平方根实际上消除了距离检查的准确性。您可以将其视为尝试获取介于1和2之间的固定点数的平方根,并将结果(介于1和sqrt(2)之间)存储在完全相同的范围内。取平方根后,某些比较为x ^ 2 <y ^ 2的距离将比较为x = y。平方长度检查既更快又更准确。
约翰·卡尔斯贝克

感谢您的出色回答bummzack和John Calsbeek!您的回答完美地回答了我的问题。我没有考虑不使用平方根而产生的额外存储空间,那里确实很不错。这启发链接为一个伟大的读
Aralox

1
A *除外。我记得读过一篇描述了不同启发式方法的测试并且d^2表现糟糕的文章。在A *中|dx| + |dy|效果很好。我一个月前读后没有链接。
乔纳森·迪金森

3
对于A *,您不仅要比较距离,还要加上距离,因此跳过sqrt确实会有所不同。
amitp'2

1
@bobobobo我同意;我主要是为了击退另一个方向上的潜在参数,即正常距离在某种程度上更准确。
John Calsbeek 2013年

14

正如bummzack在“寻路”类比中所暗示的那样,每次将距离相加并希望比较其总和时,都需要使用“正常”长度。(仅因为长度的平方和与长度的平方和不同)。

x ^ 2 + y ^ 2!=(x + y)^ 2


4

我能想到的唯一缺点是在处理大数时,平方会溢出。

例如,在Java中:

int x = Integer.MAX_VALUE / 1000000; //2147
int y = Integer.MAX_VALUE / 5000; //429496
System.out.println("x < y: " + (x < y)); //true
System.out.println("x*x: " + (x * x)); //4609609
System.out.println("y*y: " + (y * y)); //-216779712 - overflows!
System.out.println("x*x < y*y: " + (x * x < y * y)); //false - incorrect result due to overflow!

同样值得注意的是,当您使用Math.pow()使用完全相同的数字并从从以下方法返回的double中将其转换回int 时会发生什么Math.pow()

System.out.println("x^2: " + (int) (Math.pow(x, 2))); //4609609
System.out.println("y^2: " + (int) (Math.pow(y, 2))); //2147483647 - double to int conversion clamps to Integer.MAX_VALUE
System.out.println("x^2 < y^2: " + ((int) (Math.pow(x, 2)) < (int) (Math.pow(y, 2)))); //true - but for the wrong reason!

工作正常吗?,它只给出了正确的答案,因为y*y被钳制了Integer.MAX_VALUEx*x小于Integer.MAX_VALUE。如果x*x也受到限制,Integer.MAX_VALUE那么您将得到错误的答案。

类似的原理也适用于浮点数和双精度数(除非它们显然在溢出之前具有更大的范围)以及任何其他允许静默溢出的语言。


大多数人使用floats作为坐标,只有在大约10^38不之后才溢出int
bobobobo

但是在10 ^ 38时,您已经失去了太多的精度,以至于您真的不能确定距离比较是否有效-溢出不是这里的唯一问题。请参阅altdevblogaday.com/2012/02/05/dont-store-that-in-a-float(“表格”部分总结了高达10亿的精度损失)。
Maximus Minimus

sqrt(x * x)会出现相同的溢出问题。我不明白你的意思。这不是关于曼哈顿距离等等
bogglez

@bogglez-取决于您的库(或CPU)是否向上翻倍。
Maximus Minimus '18 -10-11

3

一次,我在平方距离中工作,并且由于里程表的计数而犯下了累积平方距离的错误。

当然,您不能这样做,因为在数学上,

(a^2+b^2+c^2+d^2)!=(a+b+c+d)^2

因此,我最终得到一个错误的结果。糟糕!


1
另外,我可能还会补充说,尝试使用平方距离的次数已经超过了几次,但后来发现在同一代码分支中需要实际距离。因此,请勿过度操作。有时,当您最终需要执行该sqrt操作时,在各处保持平方系数不便带来的不便。
bobobobo

3

如果编写的算法要求您计算最佳位置,则可能会遇到麻烦。例如,假设您有一组对象,并且您试图计算到所有对象的总距离最小的位置。仅举一个具体的例子,假设我们正在尝试为三座建筑物供电,并且我们想弄清楚发电厂的去向,以便我们可以使用最小的电线总长将其连接到所有建筑物。使用距离平方度量,您将最终得出电厂的x坐标为所有建筑物的x坐标的平均值(类似地,为y坐标)。使用普通距离度量,解决方案将有所不同,并且通常与距离平方解决方案相距甚远。


对于给定的情况,这是好是坏似乎是有争议的。我记得数学家在将一条线拟合到一组点时经常选择使用距离平方。也许他们这样做是因为它减少了孤立点的影响。在三层结构的情况下,离群值可能没有风险。也许他们之所以这样做,是因为x^2与之相比,使用起来更容易|x|
joeytwiddle 2015年

@joeytwiddle离群值实际影响线性回归的最小二乘拟合比绝对距离大。您说对了,因为使用起来更容易了。在我给出的示例中(即使将其修改为包含大量建筑物),距离平方度量也可以通过一个简单的公式(每个坐标的算术平均值)求解,但是绝对距离度量在数学上是难解的,并且必须使用多种数值方法之一近似求解。
亚历山大·格鲁伯

感谢您的更正。当然,您是对的,距离的平方会为离群值产生更大的误差,而不是像上面我错误地指出的那样,增加了其影响,而不是减小了。这令人着迷,最小绝对距离解决方案的计算难度更大。
joeytwiddle

0

使用距离平方几乎总是很好并且对性能有好处。以下注意事项很重要:

如果要考虑多个距离的总和,则距离平方将不准确。例如,我有两个距离,我想确保它们的总和小于10。以下代码不正确:

a = get_distance_squared(c,d);
b = get_distance_squared(e,f);
assert(a+b < 10^2);

在以下无效情况下,它无法断言:a=36b=49。在这种情况下,第一个长度是6,第二个长度是7;它们的总和大于10,但平方和不是100或更大。

另一个考虑因素:对于实值距离,距离平方将始终为正。例如,如果要测量位移,则可能需要处理负值,而对它们进行平方将不会。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.