Double nicht Genau genug!



  • Hi!
    Ich bin auf der suche nach einer bibliothek, die genauer als double rechnen kann, und dazu trigonometrische funktionen, also sin, cos, asin acos usw. unterstützt.
    Hab nämlich folgendes Problem:
    Bei folgender Rechnung und angabe gleicher Winkel entsteht ein Fehler. Die Formel berechnet die Entfernung zweiter Punkte auf einer Kugeloberfläche.
    http://upload.wikimedia.org/math/f/0/3/f03ff2d0f9150fa8c707ebc30e37ae17.png
    Geb ich jetzt gleiche Koordinanten an, so entspricht der Fehler 2000m bezogen auf die Erdoberfläche. Viel zu viel für meine Anwendung. Was kann ich da machen?

    gmp unterstützt meines wissens leider kein sinus, cosinus usw.



  • Der kleinste Wert, den man mit double darstellen kann und bei der Addition mit 1 nicht weggerundet wird, beträgt ca. 2E-16. (bei eine 8Byte double). Wenn man also den Erdumfang von ca. 40.000,00km auf 1 bezieht, so entsprächen diese 2E-16 etwa 8Pikometer also etwa im Bereich Atomarer Größenordnungen.

    Dein Problem wirst Du also mit einem genaueren double auch nicht lösen. Was bedeuten θA\theta_A, θB\theta_B, λ\lambda und ζ\zeta?

    Gruß
    Werner



  • Ich denke, dass du falsch rechnest !
    Denk daran, dass die trigonometrischen funktionen mit dem Bogenmass arbeiten !



  • Die Formel habe ich hier gefunden. Wenn man zwei gleiche Koordinaten einsetzt, berechnet sich der arccos von 1 zu den besagten 2.2E-16 - statt der korrekten 0.0. Multipliziert mit dem Erdradius von 6370km erhält man einen Wert von 0,0000014014mm.

    Wie kommst Du da auf 2000m?

    Gruß
    Werner



  • hm... komisch. hier meine rechnung:

    // p1.lat, p2.lat, p1.lon, p2.lon sind floats 
    // (ist aber ncih wichtig, wird ja dann eh in double umgewandelt)
    
    double c = sin(p1.lat)*sin(p2.lat)+cos(p1.lat)*cos(p2.lat)*(cos(p1.lon-p2.lon));
    return Radius*acos(c);
    
    ///
    Radius = 6370000.0f; // so ähnlich, aber genauer in meinem 
    // programm, hab ich grad nich zur hand
    

    da kommen bei mir 2000meter raus. ja, und ich rechne im Bogenmaß.

    float DegToRad(float d)
    {
    return d*pi/180.0f; // pi auf 15 Stellen aus dem Windows-taschenrechner
    }



  • Hallo Maxi,

    Dein Code sieht auf den ersten Blick völlig korrekt aus; ist er aber nicht. Man muss dazu wissen, dass es die trigonometrischen Funktionen sowohl für float als auch für double gibt und Du mischt beide Typen. Du berechnest den Wert für 'c' noch als float aber durch die Zuweisung nach double werden die letzen Binärstellen von 'c' nicht mit 0-en sondern mit dem Rundungsfehler von float belegt. Mit dem Ergebnis gehst Du jetzt in eine Funktion der Signatur acos( double ) hinein. die Funktion arccos hat für x=1 die Steigung unendlich. Numerisch wirkt sich also jede kleinste Änderung von x sehr stark beim Ergebnis aus.

    Dein Code würde funktionieren, wenn man durchgängig float oder durchgängig double benutzt. Nur Mischen darst Du nicht.
    Also entweder

    float c = ..;
    

    oder

    double lat, lon;
    

    Gruß
    Werner



  • aber ich dachte sin hat das argument double und sinf das argument float. Also müssten doch die floats automatisch in doubles umgewandelt werden, oder?

    wenn ich vor den sin, cos... aufrufen die floats in double uwandle funktionierts komischerweise...



  • In C++ gibt es bei sin, cos, ... overloads für float und double, d.h. es gibt

    float sin(float x);
    // und
    double sin(double x);
    

    D.h. wenn du float reintust kommt auch float raus 😉



  • achso? das wusst ich gar nihc. Ich dacht eben immer cos = double, cosf = float

    naj,a hat sich ja nun geklärt 🙂 Rechnung funktioniert auch sehr gut


Anmelden zum Antworten