Ci sono degli svantaggi nell'utilizzare i controlli del quadrato della distanza piuttosto che della distanza?


29

Uso i controlli di distanza al quadrato per praticamente tutti i miei controlli di distanza (lunghezza vettore3), a causa dell'aumento delle prestazioni dovuto al non incorrere in una radice quadrata (come nei controlli di lunghezza normale).

A quanto pare, i controlli di distanza al quadrato funzionano bene in ogni situazione:

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

Non sto prendendo in considerazione situazioni in cui x o y è inferiore a 0, poiché la distanza e la distanza al quadrato saranno sempre positive.

Dal momento che funziona, sembra che i controlli a distanza non siano mai necessari, ma ho la fastidiosa sensazione che mi manchi qualcosa. Ciò continuerà a resistere in situazioni critiche per la precisione?

Risposte:


41

Non ho alcun svantaggio di cui sono a conoscenza quando uso la lunghezza quadrata per confrontare le distanze. Pensaci in questo modo: stai solo saltando il sqrtche non ti dà alcuna precisione aggiuntiva. Se non hai bisogno dell'attuale distanza euclidea, allora puoi tranquillamente lasciare sqrtfuori.

Ovviamente la lunghezza quadrata si ridimensiona in modo abbastanza diverso dalla distanza euclidea ed è quindi un cattivo candidato per cose come l'euristica del pathfinding .


16
La radice quadrata rimuove effettivamente la precisione dal controllo della distanza. Puoi pensarlo come un tentativo di prendere la radice quadrata di un numero di punto fisso tra 1 e 2 e memorizzare il risultato (tra 1 e sqrt (2)) esattamente nello stesso intervallo. Alcune distanze che si confrontano come x ^ 2 <y ^ 2 verranno confrontate come x = y dopo aver preso la radice quadrata. Il controllo della lunghezza al quadrato è sia più veloce che più preciso.
John Calsbeek,

Grazie per le tue eccellenti risposte bummzack e John Calsbeek! Le tue risposte combinate rispondono perfettamente alla mia domanda. Non ho considerato lo spazio di memoria aggiuntivo dal non usare una radice quadrata, pickup davvero bello lì. E quel collegamento euristico è un'ottima lettura
Aralox,

1
Tranne nel caso di A *. Ricordo di aver letto un articolo che descriveva i test di diverse euristiche e si è d^2comportato in modo orribile. In A * |dx| + |dy|funziona bene. Non ho il link mentre leggo circa un mese fa.
Jonathan Dickinson,

3
Nel caso di A * non stai semplicemente confrontando le distanze, ma le aggiungi, quindi saltare sqrt fa la differenza.
tra il

1
@bobobobo Sono d'accordo; Per lo più ci sono riuscito per abbattere un potenziale argomento nell'altra direzione, vale a dire che la distanza normale in qualche modo era più precisa.
John Calsbeek,

14

Come ha accennato Bummzack con l'analogia del Path-tracking, DEVI usare la lunghezza "normale" ogni volta che aggiungi le distanze insieme e vuoi confrontare la loro somma. (Solo perché le somme dei quadrati delle lunghezze sono diverse dalle somme quadrate delle lunghezze).

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


4

L'unico svantaggio che mi viene in mente è quando ho a che fare con grandi numeri che traboccano quando sono al quadrato.

Ad esempio, in 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!

Vale anche la pena notare che è ciò che accade quando si utilizza Math.pow () con gli stessi numeri esatti e si esegue il cast su int dal doppio restituito da 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!

Funziona? No , ha dato solo la risposta corretta perché y*yè bloccato a Integer.MAX_VALUEed x*xè inferiore a Integer.MAX_VALUE. Se x*xfosse anche bloccato a Integer.MAX_VALUEallora otterresti una risposta errata.

Principi simili si applicano anche con float e doppi (tranne per il fatto che ovviamente hanno un raggio maggiore prima di traboccare) e qualsiasi altra lingua che consenta silenziosamente trabocchi.


La maggior parte delle persone utilizzano floats per le coordinate, che solo troppo pieno dopo circa 10^38non int.
Bobobobo,

Ma a 10 ^ 38 hai perso così tanta precisione che non puoi davvero essere sicuro che i tuoi confronti di distanza siano più validi - l'overflow non è l'unico problema qui. Vedi altdevblogaday.com/2012/02/05/dont-store-that-in-a-float (la sezione "Tabelle" riassume le perdite di precisione fino a 1 miliardo).
Maximus Minimus

Avrai lo stesso problema di overflow con sqrt (x * x). Non vedo il tuo punto. Non si tratta della distanza di Manhattan, ecc.
Bogglez

@bogglez - dipende dal fatto che la tua libreria (o CPU) esegua l'upgrade per raddoppiare o meno.
Maximus Minimus,

3

Una volta stavo lavorando a distanze quadrate e ho fatto l'errore di accumulare distanze quadrate, per un conteggio del contachilometri.

Certo, non puoi farlo, perché matematicamente,

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

Quindi, ho finito con un risultato errato lì. Oops!


1
Potrei anche aggiungere che ci sono state più volte in cui ho provato a utilizzare le distanze al quadrato, solo per scoprire che avevo bisogno di distanze effettive in seguito nello stesso ramo di codice. Quindi, non esagerare. A volte non vale la pena l'inconveniente di mantenere i coefficienti quadrati ovunque, quando è necessario finire sqrtcomunque l' operazione.
bobobobo,

3

Potresti incorrere in problemi se stai scrivendo un algoritmo che richiede di calcolare una posizione ottimizzata. Ad esempio, supponiamo che tu avessi una serie di oggetti e stavi cercando di calcolare la posizione con la minima distanza totale da tutti gli oggetti. Solo per un esempio concreto, supponiamo che stiamo cercando di alimentare tre edifici e vogliamo capire dove dovrebbe andare la centrale elettrica in modo da poterla collegare a tutti gli edifici utilizzando la minima lunghezza totale del filo. Usando la metrica del quadrato della distanza, finiresti con la coordinata x della centrale elettrica che è la media delle coordinate x di tutti gli edifici (e analogamente per la coordinata y). Usando la metrica della distanza ordinaria, la soluzione sarebbe diversa e spesso molto lontana dalla soluzione al quadrato della distanza.


Sembra discutibile quale sarebbe meglio o peggio per una data situazione. Ricordo che i matematici spesso scelgono di usare il quadrato della distanza quando si adatta una linea a una serie di punti. Forse lo fanno perché riduce l'influenza dei valori anomali solitari. Nel tuo caso di tre edifici, i valori anomali potrebbero non essere un rischio. O forse lo fanno perché x^2è più facile lavorare con |x|.
joeytwiddle,

Gli outlier di @joeytwiddle in realtà influenzano la regressione lineare più con adattamenti minimi quadrati che distanza assoluta. Hai ragione che è usato perché è più facile lavorare con. Nell'esempio che ho fornito (anche se modificato per contenere un gran numero di edifici), la metrica della distanza al quadrato viene risolta con una formula semplice (la media aritmetica di ciascuna coordinata), ma la metrica della distanza assoluta è matematicamente intrattabile e deve essere risolto approssimativamente usando uno dei numerosi metodi numerici.
Alexander Gruber il

Grazie per la correzione. Naturalmente hai ragione, il quadrato della distanza genera un errore più grande per i valori anomali, aumentando la loro influenza anziché ridurla, come ho erroneamente affermato sopra. È affascinante quanto sia più difficile calcolare la soluzione a distanza assoluta minima.
Joeytwiddle,

0

L'uso della distanza al quadrato è quasi sempre perfetto e buono per le prestazioni. Le seguenti considerazioni sono importanti:

Se vuoi pensare alla somma di un numero di distanze, la distanza al quadrato sarà imprecisa. Ad esempio, ho due distanze e voglio assicurarmi che la loro somma sia inferiore a 10. Il codice seguente non è corretto:

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

Non riesce ad affermare nel seguente caso non valido: a=36e b=49. In questo caso, la prima lunghezza è 6 e la seconda 7; la loro somma è maggiore di 10, ma la somma dei quadrati non è 100 o maggiore.

Un'altra considerazione: per distanze con valori reali, la distanza al quadrato sarà sempre positiva. Se, ad esempio, stai misurando lo spostamento, potresti dover gestire valori negativi e la loro quadratura non funzionerà.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.