Optimierung einer Entfernungsberechnungsfunktion

8

In meinem Code muss eine große Distanzberechnung zwischen Paaren von Längen- und Breitenwerten durchgeführt werden.

Der Code sieht so aus:

%Vor%

(lat2rad ist beispielsweise der Breitengrad, der in Radianten umgewandelt wird).

Ich habe diese Funktion als Leistungsengpass meiner Anwendung identifiziert. Gibt es eine Möglichkeit, dies zu verbessern?

(Ich kann keine Nachschlagetabellen verwenden, da die Koordinaten variieren). Ich habe mir auch diese Frage wo ein Suchschema wie ein Gitter vorgeschlagen wird, was eine Möglichkeit sein könnte.

Danke für Ihre Zeit! ; -)

    
puls200 05.03.2009, 15:17
quelle

12 Antworten

5

Wenn es Ihr Ziel ist, Entfernungen zu vergleichen (), können Approximationen ( sin und cos -Tabellen-Lookups) die Anzahl der erforderlichen Berechnungen drastisch reduzieren (implementieren Sie quick reject .)

Ihr Ziel ist es, nur mit der tatsächlichen trigonometrischen Berechnung fortzufahren, wenn die Differenz zwischen den approximierten Entfernungen (die zu bewerten oder zu vergleichen sind) unter einen bestimmten Schwellenwert fällt.

z. unter Verwendung von Nachschlagetabellen mit 1000 Abtastwerten (d. h. sin und cos alle 2*pi/1000 abgetastet) beträgt die Nachschlagetunsicherheit höchstens 0,006284. Unter Verwendung der Unsicherheitsberechnung für den Parameter ACos ist die kumulierte Unsicherheit auch die Schwellenunsicherheit , wird höchstens 0,018731 sein.

Wenn also Math.Sin(lat2rad) * Math.Sin(lat1rad) + Math.Cos(lat2rad) * Math.Cos(lat1rad) * Math.Cos(lon2rad - lon1rad) unter Verwendung von sin und cos Nachschlagetabellen für zwei Koordinatenpaare (Distanzen) berechnet wird, ergibt sich eine bestimmte Rangfolge (eine Distanz erscheint größer als die andere basierend auf der Approximation) und die Differenz Modulus ist größer als der obige Schwellenwert, dann ist die Approximation gültig. Andernfalls fahren Sie mit der eigentlichen trigonometrischen Berechnung fort.

    
vladr 05.03.2009, 15:48
quelle
4

Würde der CORDIC -Algorithmus für Sie (in Bezug auf Geschwindigkeit / Genauigkeit) funktionieren?

    
Brian Knoblauch 05.03.2009 15:31
quelle
3

Mit Inspiration von @Brann Ich denke, dass Sie die Berechnung ein wenig reduzieren können (Warnung, es ist lange her, seit ich das getan habe und es muss verifiziert werden). Eine Art Nachschlagen vorberechneter Werte ist wahrscheinlich die schnellste, obwohl

Sie haben:

1: ACOS (SIN A SIN B + COS A COS B COS (A-B))

aber 2: COS (A-B) = SIN A SIN B + COS A COS B

, das als 3 umgeschrieben wird: SIN A SIN B = COS (A - B) - COS A COS B

ersetzen Sie SIN A SIN B in 1. Sie haben:

4: ACOS (COS (A-B) - COS A COS B + COS A COS B COS (A-B))

Sie rechnen X = COS (A-B) vor und Y = COS A COS B und Sie setzen die Werte in 4

geben:

ACOS (X - Y + XY)

4 trigonometrische Berechnungen statt 6!

    
Tom Carter 05.03.2009 15:54
quelle
2

Ändern Sie die Art, wie Sie long / lat speichern:

%Vor%

Wenn Sie ein long / lat erstellen, berechnen Sie auch den (x, y, z) 3D-Punkt, der die äquivalente Position auf einer Einheitskugel darstellt, die am Ursprung zentriert ist.

Um festzustellen, ob Punkt B näher an Punkt A als Punkt C ist, gehen Sie wie folgt vor:

%Vor%

und um die Entfernung zwischen zwei Punkten zu erhalten:

%Vor%

Sie könnten den Begriff "Radius" entfernen, um die Abstände zu normalisieren.

    
Skizz 05.03.2009 16:05
quelle
1

Wechsel zu Nachschlagetabellen für sin / cos / acos. Wird schneller sein, es gibt viele c / c ++ Fixed-Point-Bibliotheken, die auch diese enthalten.

Hier ist Code von jemand anderem auf Memoization . Das könnte funktionieren, wenn die tatsächlichen Werte mehr geclustert sind.

Hier ist eine SO-Frage zu Fixed Point .

    
sfossen 05.03.2009 15:30
quelle
1

Was ist der Flaschenhals? Ist die Sinus / Cosinus-Funktion oder der Arcsine-Aufruf?

Wenn Ihre Sinus / Cosinus-Aufrufe langsam sind, können Sie den folgenden Satz verwenden, um so viele Aufrufe zu verhindern:

%Vor%

Aber ich mag die Mapping-Idee, damit Sie die Werte, die Sie bereits berechnet haben, nicht neu berechnen müssen. Seien Sie vorsichtig, da die Karte sehr schnell sehr groß werden kann.

    
user17720 05.03.2009 15:57
quelle
0

Wie genau brauchen Sie die Werte?

Wenn Sie Ihre Werte etwas runden, können Sie das Ergebnis aller Nachschlagevorgänge speichern und prüfen, ob sie vor jeder Berechnung verwendet wurden.

    
Peter 05.03.2009 15:25
quelle
0

Nun, da lat und lon garantiert innerhalb eines bestimmten Bereichs liegen, könnten Sie versuchen, eine Form einer Nachschlagetabelle für Ihre Math. * Methodenaufrufe zu verwenden. Sagen wir, ein Dictionary<double,double>

    
Muad'Dib 05.03.2009 15:34
quelle
0

Ich würde argumentieren, dass Sie vielleicht noch einmal untersuchen möchten, wie Sie diese Funktion als Engpass gefunden haben. (IE haben Sie die Anwendung profiliert?)

Die Gleichung für mich scheint sehr gering und sollte keinen Ärger verursachen. Zugegeben, ich kenne Ihre Anwendung nicht und Sie sagen, dass Sie viele dieser Berechnungen durchführen.

Trotzdem ist es etwas zu beachten.

    
Gavin Miller 05.03.2009 16:02
quelle
0

Wie jemand anders gesagt hat, sind Sie sicher, dass dies Ihr Flaschenhals ist?

Ich habe Leistungstests für eine ähnliche Anwendung durchgeführt, die ich gerade erstelle, wo ich eine einfache Methode nenne, um einen Abstand zwischen zwei Punkten mithilfe der Standardtriggerung zurückzugeben. 20.000 Aufrufe dazu schieben es direkt an die Spitze der Profiling-Ausgabe, aber es gibt keine Möglichkeit, dass ich es schneller machen kann ... Es ist nur die Schar von Anrufen.

In diesem Fall muss ich die # Aufrufe reduzieren ... Nicht, dass dies der Flaschenhals ist.

    
Ian 05.03.2009 16:13
quelle
0

Ich benutze einen anderen Algorithmus für die Berechnung der Entfernung zwischen 2 Lati / Longi-Positionen, es könnte leichter sein als deins, da es nur 1 Cos Call und 1 Sqrt Call macht.

%Vor%     
Akhena 05.03.2009 16:28
quelle
0

Jemand hat Memoisierung bereits erwähnt, und das ist ein bisschen ähnlich. Wenn Sie denselben Punkt mit vielen anderen Punkten vergleichen, ist es besser, Teile dieser Gleichung vorher zu berechnen.

statt

%Vor%

habe:

%Vor%

und ich denke, das ist die gleiche Formel wie jemand anders gepostet hat, weil ein Teil der Gleichung verschwinden wird, wenn Sie die Klammern erweitern:)

    
drscroogemcduck 05.03.2009 17:09
quelle

Tags und Links