Genauigkeit (long) double



  • Hallo zusammen,

    ich hab hier schon ein paar Einträge bezüglich der Genauigkeit bezüglich der Zahlen in C++ gelesen. Altes Thema und Recht interessant, vor allem da meine Kollegen letzte Woche auf einer Konferenz waren und anscheinend gab es dort auch einen Talk über diesbezüglich. In meinem Projekt habe ich nun folgendes Problem

    Ich muss mit Zahlenwerten hantieren, die zur 40ten Potenz sind. Ein konkrete Beispiel wäre die zahl .1000E+29, die als String eingelesen wird und in ein (long) Double Variable gespeichert wird. Geb ich diese nun aus, erhalte ich 1e-30 als Zahlenwert. Erhöhe ich die Genauigkeit der Ausgabe mit setprecision(50) kommt sowas raus:

    1000000000000000019884624838656
    

    Bei den negativen Potenzen macht mir das nichts aus aber bei einer Berechnung mit der oben genannten Zahl ist das Ergebnis natürlich schon anders. Was mich auch stuzig macht, long double und double geben mir beide dieses Ergebnis aus. Meine Frage an euch, da ich das aus den anderen Diskussionen nicht herauslesen konnte bzw. nicht darüber diskutiert wurde. Was macht man in solch einem Fall? Ist es allgemein so, dass man sich damit abfindet und die Fehler einfach akzeptiert und wieso liefert long double und double das gleiche Ergebnis?

    Danke schon im voraus,
    Tobi


  • Mod

    Shor-ty schrieb:

    Ich muss mit Zahlenwerten hantieren, die zur 40ten Potenz sind. Ein konkrete Beispiel wäre die zahl .1000E+29, die als String eingelesen wird und in ein (long) Double Variable gespeichert wird. Geb ich diese nun aus, erhalte ich 1e-30 als Zahlenwert.

    Sei präziser wenn du deine Beiträge verfasst. Ich habe gerade keine Ahnung, welchen Bezug diese drei Zahlen zu einander haben, weil 40, -30 und 29 ziemlich verschieden sind (der Tippfehler in der ersten wissenschaftlich notierten hilft auch nicht!).



  • Tja, hängt vom Compiler ab.

    Bei mir:

    root [22] sizeof(long double)
    (unsigned long) 16
    root [23] sizeof(double)
    (unsigned long) 8
    root [24] cout << setprecision(50) << .1000E+29L << " versus " << .1000E+29 << endl;
    9999999999999999999731564544 versus 9999999999999999583119736832
    

    Der C++-Standard sagt, dass long double mindestens so genau ist wie double . Es muss also nicht unbedingt genauer sein.

    Was macht man? Tja, kommt auf das Problem an! Entweder die Genauigkeit ist ausreichend: dann freuen. Oder sie reicht nicht. Dann entweder überlegen, ob es nicht einen numerisch stabileren Algorithmus gibt, der auf das Ziel führt - wenn nicht, ggf. spezielle Bibliothek nutzen, die dir höhere Genauigkeiten ermöglicht.



  • Arcoth schrieb:

    Shor-ty schrieb:

    Ich muss mit Zahlenwerten hantieren, die zur 40ten Potenz sind. Ein konkrete Beispiel wäre die zahl .1000E+29, die als String eingelesen wird und in ein (long) Double Variable gespeichert wird. Geb ich diese nun aus, erhalte ich 1e-30 als Zahlenwert.

    Sei präziser wenn du deine Beiträge verfasst. Ich habe gerade keine Ahnung, welchen Bezug diese drei Zahlen zu einander haben, weil 40, -30 und 29 ziemlich verschieden sind (der Tippfehler in der ersten wissenschaftlich notierten hilft auch nicht!).

    Hi,

    da geb ich dir vollkommen recht. Das in meiner Angabe macht hier keinen Sinn (Tippfehler). Das Beispiel bezog sich auf .1000E+31.

    std::string test = ".1000E+31"
    
    double number = stod(test);
    
    std::cout << "String: " << test << "\n";
    std::cout << "Number: " << number << "\n";
    std::cout << "Number: " << setprecision(50) << number << "\n";
    

    Die Ausgabe ist:

    String: .1000E+31
    Number: 1.000E+30
    Number: 1000000000000000019884624838656
    

    @wob... danke für deine Info. Schau, ich hab noch nicht mal geprüft wie genau bei mir double und long double ist. Okay das ist geklärt; hätte ich eigentlich auch wissen sollte. Bezüglich der zweiten Aussage. Ich schau mir die Berechnungen im Detail an.

    Was mich gerade noch interessiert. Wenn ich die oben genannte Zahl nun für Berechnungen verwende, dann wird schon die komplett ausgeschriebene Zahl verwendet oder? Ich dachte auch schon daran, die Zahlen mittels dem Logarithmus darzustellen (war natürlich nur ein Gedanke).



  • Um dein neues Beispiel hier anzugucken:

    root [26] std::string test = ".1000E+31" 
    (std::string &) ".1000E+31"
    root [27] double number = stod(test); 
    root [28] cout << number << endl;
    1000000000000000019884624838656
    root [29] auto n2 = stold(test)
    (long double) 1e+30L
    root [30] cout << n2 << endl;
    1000000000000000000024696061952
    root [31] n2 - number
    (long double) -1.98599e+13L
    

    "Mein" long double schafft also 3 Nullen mehr.

    Shor-ty schrieb:

    Was mich gerade noch interessiert. Wenn ich die oben genannte Zahl nun für Berechnungen verwende, dann wird schon die komplett ausgeschriebene Zahl verwendet oder? Ich dachte auch schon daran, die Zahlen mittels dem Logarithmus darzustellen (war natürlich nur ein Gedanke).

    Und ja, in Berechnungen wird natürlich die "komplett ausgeschriebene Zahl" verwendet. Wobei ich die Formulierung etwas unglücklich finde, denn umgekehrt ist es ja: es ist eine Zahl im Speicher (in irgendeiner Darstellung, normalerweise IEEE 754), die irgendwie ins 10er-System umgewandelt und dargestellt werden muss. Wenn du also 0.1 hast, was in IEEE754 nicht darstellbar ist, dann hast du in Wirklichkeit eine andere Zahl in deiner Variablen. Nur beim Darstellen wird dir dann ggf. 0.1 oder 0.1+-ungenauigkeit angezeigt.

    Ansonsten schau dir mal sowas wie http://www.mpfr.org/ an. Aber oftmals reicht double aus, wenn man es klug anstellt. Wobei... ich weiß ja nicht, was du für Anforderungen hast.



  • PS: vielleicht guckst du dir auch mal den Header limits an, insbesondere std::numeric_limits<T>::digits10

    Hier kommt raus:
    T=float: 6, T=double: 15, T=long double: 18.



  • Du solltest Dir vielleicht erst mal Gedanken darüber machen, ob Du über Präzision oder Genauigkeit sprichtst
    https://de.wikipedia.org/wiki/Genauigkeit

    Bsp.: Wenn Deine Eingaben nur vier Stellen in der Mantisse haben, weisst Du nicht, was ab der fünften Stelle der präzise Wert ist. Auf die Genauigkeit Deiner Darstellung hat das keinen Einfluss mehr.

    Vielleicht solltest Du auch noch lesen:
    http://perso.ens-lyon.fr/jean-michel.muller/goldberg.pdf



  • Hallo zusammen,

    vielen Dank für die ganzen Anmerkungen, Schlüsselwörter und Links. Referenzen und Lesestoff ist immer gut zu haben. Zudem ist es (wie so oft) wichtig die richtigen Forumlierung zu treffen (Genauigkeit vs. Präzision). Wiedermal vielen Dank.

    Ich denke damit komm ich erstmal sehr viel weiter.


Anmelden zum Antworten