거리가 아닌 거리 제곱 검사를 사용할 때의 단점이 있습니까?


29

평범한 길이 검사와 같이 제곱근이 발생하지 않아 성능이 향상되므로 기본적으로 모든 거리 (vector3 길이) 검사에 거리 제곱 검사를 사용합니다.

외관상 제곱 거리 검사는 모든 상황에서 잘 작동합니다.

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

거리와 거리 제곱이 항상 양수이므로 x 또는 y가 0보다 작은 상황은 고려하지 않습니다.

이것이 작동하기 때문에 거리 확인이 결코 필요하지 않은 것처럼 보이지만 뭔가 빠진 느낌이 들었습니다. 이것이 여전히 정확한 상황에서 견딜 수 있습니까?

답변:


41

거리를 비교하기 위해 제곱 길이를 사용할 때 알고있는 단점은 없습니다. 다음과 같이 생각해보십시오 sqrt. 추가 정확도를 제공하지 않는 것을 건너 뛰는 것 입니다. 실제 유클리드 거리가 필요하지 않은 경우 안전하게 벗어날 수 있습니다 sqrt.

물론 제곱 길이는 유클리드 거리와는 상당히 다른 스케일 을 가지 므로 길 찾기 휴리스틱과 같은 것들에 대한 나쁜 후보입니다 .


16
제곱근은 실제로 거리 확인에서 정확도를 제거합니다. 1과 2 사이의 고정 소수점 수의 제곱근을 취하고 결과를 1과 sqrt (2) 사이의 정확히 같은 범위에 저장하려는 시도로 생각할 수 있습니다. x ^ 2 <y ^ 2와 비교되는 일부 거리는 제곱근을 취한 후 x = y로 비교됩니다. 제곱 길이 검사는 더 빠르고 정확합니다.
존 Calsbeek

훌륭한 답변 bummzack과 John Calsbeek에게 감사합니다! 귀하의 답변은 내 질문에 완벽하게 답변합니다. 나는 제곱근을 사용하지 않는 추가 메모리 공간을 고려하지 않았습니다. 정말 좋은 픽업입니다. 그리고 그 휴리스틱 링크는 대단한 읽기를 만듭니다
Aralox

1
A *의 경우를 제외하고. 나는 다른 휴리스틱의 테스트를 설명하고 d^2끔찍한 기사를 읽은 것을 기억 합니다. A *에서는 |dx| + |dy|잘 작동합니다. 한 달 정도 읽었을 때 링크가 없습니다.
Jonathan Dickinson

3
A *의 경우 단순히 거리를 비교하는 것이 아니라 거리를 더하는 것이므로 sqrt를 건너 뛰면 차이가 있습니다.
amitp

1
@bobobobo 동의합니다. 나는 주로 다른 방향으로, 즉 일반적인 거리가 더 정확한 다른 방향으로 잠재적 인 논쟁을 격추하도록 만들었다.
존 Calsbeek

14

bummzack이 Path-finding 유추를 암시했듯이 거리를 더하고 합계를 비교할 때마다 "정상"길이를 사용해야합니다. (길이 제곱의 합이 길이의 제곱 합과 다르기 때문에).

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_VALUE있고 x*x보다 작기 때문에 정답 만 제공합니다 Integer.MAX_VALUE. 경우 x*x에도 고정 된 Integer.MAX_VALUE당신은 잘못된 답변을 얻을 것입니다.

비슷한 원리가 floats & doubles (오버플로 전에 분명히 더 큰 범위를 제외하고)와 오버플로를 자동으로 허용하는 다른 언어에도 적용됩니다.


대부분의 사람들이 사용하는 float좌표의 만 오버 플로우 후 약 10^38되지 않음 int.
bobobobo

그러나 10 ^ 38에서 거리 정밀도가 더 이상 유효하다는 것을 실제로 확신 할 수 없을 정도로 정밀도가 떨어졌습니다. 오버플로가 유일한 문제는 아닙니다. altdevblogaday.com/2012/02/05/dont-store-that-in-a-float ( "테이블"섹션은 최대 10 억 개의 정밀 손실을 요약합니다)를 참조하십시오 .
Maximus Minimus 2018 년

sqrt (x * x)와 동일한 오버플로 문제가 있습니다. 나는 당신의 요점이 보이지 않습니다. 이것은 맨하탄 거리 등에 관하여이지 않는다
bogglez

@bogglez-라이브러리 (또는 CPU)가 두 배로 업 캐스트되는지 여부에 따라 다릅니다.
Maximus Minimus

3

한 번은 제곱 거리에서 일하고 있었고 거리계 수로 제곱 거리 를 누적 하는 실수를 저질렀습니다 .

물론 수학적으로는이 작업을 수행 할 수 없습니다.

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

그래서 나는 잘못된 결과를 얻었습니다. 죄송합니다!


1
또한 제곱 거리를 사용하려고 시도한 경우가 몇 번 이상 있었으며 나중에 동일한 코드 분기에서 실제 거리가 필요하다는 것을 알았습니다 . 따라서 과용하지 마십시오. sqrt어쨌든 작업 을 끝내야 할 때 사방 제곱 계수를 유지하는 것이 불편할 가치가 있습니다 .
bobobobo

3

최적화 된 위치를 계산해야하는 알고리즘을 작성하는 경우 문제가 발생할 수 있습니다. 예를 들어, 객체 집합이 있고 모든 객체에서 총 거리가 가장 작은 위치를 계산하려고한다고 가정 해 봅시다. 구체적인 예를 들어, 우리는 3 개의 건물에 전력을 공급하려고하는데, 가장 작은 총 길이의 와이어를 사용하여 모든 건물에 연결할 수 있도록 발전소가 어디로 가야하는지 파악하려고합니다. 거리 제곱 측정법을 사용하면 발전소의 x 좌표가 모든 건물의 x 좌표의 평균이됩니다 (y 좌표와 유사). 일반적인 거리 측정법을 사용하면 솔루션이 다르고 종종 거리 제곱 솔루션에서 멀리 떨어져 있습니다.


주어진 상황에서 더 좋거나 나쁠 것 같은 논쟁의 여지가 있습니다. 나는 수학자들이 선을 점 세트에 맞출 때 거리 제곱을 사용하기로 선택한다는 것을 기억합니다. 아마도 그들은 고독한 특이 치의 영향을 줄이기 때문에 그렇게합니다. 3 건의 경우 특이 치는 위험하지 않을 수 있습니다. 또는 x^2보다 쉽게 ​​작업 할 수 있기 때문에 아마도 그렇게 할 것 |x|입니다.
joeytwiddle

@joeytwiddle 특이 값은 실제로 절대 거리보다 최소 제곱 적합으로 선형 회귀에 더 영향을줍니다. 작업하기가 쉽기 때문에 사용하는 것이 옳습니다. 내가 준 예제에서 (많은 건물을 포함하도록 수정 된 경우에도) 거리 제곱 메트릭은 간단한 공식 (각 좌표의 산술 평균)으로 해결되지만 절대 거리 메트릭은 수학적으로 다루기 어려워 야합니다. 대략 다수의 수치 방법 중 하나를 사용하여 해결되었습니다 .
Alexander Gruber

수정 해 주셔서 감사합니다. 물론 당신이 맞습니다 . 위의 잘못 언급 한 것처럼 거리 의 제곱 은 이상치에 대해 더 큰 오차를 생성하여 영향을 줄이지 않고 영향을 증가시킵니다. 가장 절대 거리가 가장 어려운 솔루션을 계산하는 것이 얼마나 어려운지 흥미 롭습니다.
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 이상이 아닙니다.

또 다른 고려 사항 : 실제 거리의 경우 거리 제곱은 항상 양수입니다. 예를 들어 변위를 측정하는 경우 음수 값을 처리해야 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.