Anzahl der Nachkommastellen variable gestallten



  • Hallo zusammen!

    Ich möchte Gleitkommazahlen mit alle Nachkommastellen der jeweiligen Zahl in ein Textfile schreiben. Gibt es nur eine Nachkommastelle soll auch nur eine ausgegeben werden, damit das File nicht unnötig groß wird. Mit der unten stehenden Formatierung ergibt sich das Problem, dass bei sechs Nachkommastellen abgeschnitten wird. Dies ist leider auch nicht akzeptabel (zu ungenau).

    fprintf (Meintextfile,"%f",x);

    Beispiel wie es sein sollte:
    x = 1 Ausgabe x = 1
    x = 10.1 Ausgabe x = 10.1
    x = 10.14613215642154 Ausgabe x = 10.14613215642154

    Vielleicht kann mir jemand eine Tipp geben wie ich dieses Problem lösen könnte

    Besten Dank für eure Hilfe
    lg





  • Gleitkommazahlen sind keine Dezimal-Zeichenketten. Zum Beispiel ist die Zahl 0,1 typischerweise als binäre Gleitkommazahl nicht exakt darstellbar. Im Binärsystem ist das nämlich

    dezimal: 0,1
    binär:   0,000110011001100110011001100110011001100110011001100110011001100... 
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                             die 52 signifikantesten Bits
    
                            endliche, gerundete Binärzahl:
    
    binär:   0,0001100110011001100110011001100110011001100110011001101
    dezimal: 0,1000000000000000083...
    

    Eine Gleitkommazahl speichert nur eine endliche Zahl von signifikanten Bits. Bei 64Bit Gleitkommazahlen sind das typischerweise 52 Bits. Die restlichen gehen für das Vorzeichen und den Exponenten drauf, der sagt, wo das Komma hinkommt (daher "Fließkomma"). Genauer: Das führende Bit ist immer 1, braucht also nicht gespeichert werden (macht 51 bits) + vorzeichen (1 bit) + exponent (12 bits) = 64 bits. Dann gibt es natürlich noch Sonderfälle (denormalisierte Zahlen, Unendlich, Not-a-Number, etc)

    Fließkommazahlen und Dezimaldarstellung in Form von Zeichenketten können aber hin und herkonvertiert werden. Handelt es sich um eine IEEE-754 Gleitkommazahl mit 64 bits dann benötigst Du für eine verlustfreie Rundreise

    double -> string -> double

    17 signifikante Dezimalstellen und eine gescheite Implementierung der Standardbibliothek bzgl Konvertierung. Bist Du an einer verlustfreien Rundreise

    string -> double -> string

    interessiert, wobei ich "0.123" und "0.123000" als äquivalentente Zeichenketten betrachten würde, darf die Kommazahl im Eingangsstring nicht mehr als 15 signifikante Dezimalstellen besitzen. Mehr gibt die Genauigkeit von double (typischerweise) nicht her.

    Es gibt neben IEEE-754 noch andere Gleitkomma-Formate und C++ schreibt die genaue Darstellung nicht vor, nur eine gewisse Mindestgenauigkeit von float, double und long double. Aber IEEE-754 ist recht populär.



  • Danke für die raschen und ausführlichen Antworten!

    Leider hilft mir das nicht wirklich weiter bzw. verstehe ich es nicht ganz!
    Ich versuch mal mein Problem näher zu schildern:

    Ich schreibe ein Konvertierungsprogramm. Es ließt über eine DLL Messdaten ein und soll diese dann in ein Textfile schreiben.

    Die DLL gibt mir double Werte zurück. Es werden verschiedenste Zahlenwerte eingelesen zB.: Geschwindigkeiten und Beschleunigung meist mit 2 oder 3 Nachkommastellen und unter anderem auch GPS-Daten in Dezimalgrad, wo ich mindestens 8 Nachkommstellen für die gewünschten Genauigkeit benötige.
    Wenn ich jetzt alle Zahlenwerte mit 8 Nachkommastellen ausgeben um auf der sicheren Seite zu sein, dann wird bei 1 Million Messwerte der Unterschied in der Filegröße nicht mehr vernachlässigbar.

    Hier mal mein Quellcode stark vereinfacht:

    double x = getMesswert_i_fromDLL(i);
    //hier steht nun wenn ich x in Debugmodus anschaue z.B.: x = 10.1 ; x =143.34456346
    fprintf(MeinTXT,"%f\n",x); // und genau so will ich es im Textfile stehen haben
    

    Alle mir bekannten Formatierungen wie %f, %g, .. machen das auch so schneiden aber leider bei 6 Nachkommastellen ab ich brauche aber mindesten 8!!

    Ich hoffe mein Problem ist jetzt etwas besser erklärt!

    Danke schon mal an alle für eure Hilfe
    lg


  • Mod

    Da du im C++ Forum fragst, nehme ich mal trotz deines C-Codes optimistischerweise an, dass du eine C++ Lösung suchst. Führ mal dieses Programm aus und spiel mit den Werten für precision:

    // modify basefield
    #include <iostream>
    using namespace std;
    
    int main () {
      double a,b,c;
      a = 3.1415926534;
      b = 2006.0;
      c = 1.0e-10;
      cout.precision(5);
      cout       <<         a << '\t' << b << '\t' << c << endl;
      cout <<   fixed    << a << '\t' << b << '\t' << c << endl;
      cout << scientific << a << '\t' << b << '\t' << c << endl;
      return 0;
    }
    

    Somit sollte dir klar werden, wie das mit den Nachkommastellen funktioniert und was für dich das richtige ist.

    Für C gibt es auch äquivalente Lösungen.



  • Das ist in der Tat etwas umständlich, aber wenn man die C++Streams verwendet, sollte das Problem sich gar nicht ergeben:

    fstream myfile;
    myfile.open("C:\\wo\\auch\\immer\\sie\\liegt\\datei.txt", ios::out);
    if (myfile)
        myfile << x1 << "; " << x2 << endl;
    


  • .open() existiert nicht!



  • 314159265358979 schrieb:

    .open() existiert nicht!

    Wenn das ein Witz sein soll, dann ist er wirklich schlecht.

    http://www.cplusplus.com/reference/iostream/fstream/open/


  • Mod

    [Rewind] schrieb:

    314159265358979 schrieb:

    .open() existiert nicht!

    Wenn das ein Witz sein soll, dann ist er wirklich schlecht.

    http://www.cplusplus.com/reference/iostream/fstream/open/

    Er spielt darauf an, dass das open, genau wie das close, eines Dateistreams eher eine Funktion ist, die man nur in Ausnahmefällen braucht. Beide werden jedoch sehr oft von Leuten benutzt, die C++ wie C programmieren und sich dieser Tatsache gar nicht bewusst sind.



  • Dann nimmt man eben

    fstream myfile("C:\\wo\\auch\\immer\\sie\\liegt\\datei.txt");
    

    Ich lasse mich immer gerne eines Besseren belehren, aber was ist daran verkehrt, die in C++-Standardbibliotheken implementierten Funktionen zu verwenden? 😕 Macht mich das automatisch zum C-Programmierer? :totally confused:


  • Mod

    Es ist eben unschön, weil man erst ein uninitialisiertes Objekt erzeugt und dieses dann erst noch mittels einer Memberfunktion in einen gebrauchsbereiten Zustand versetzen muss. Dies läuft den Grundprinzipien der objektorientierten Programmierung zuwider.
    Wenn man das trotzdem macht zeigt man auch, dass man sich nicht richtig mit den Standardfunktionen und mit gutem Stil auskennt.

    Abgesehen davon ist es auch schlichtweg länger zu schreiben. Und gefährlicher, denn man könnte potentiell ein uninitialisiertes Objekt benutzen oder das open kann fehlschlagen, weil der Stream schon an eine andere Datei gebunden sein könnte.



  • Um nochmal zu deinem printf Problem zu kommen:
    Im Formatstring bei printf kann man selbstverständlich auch die Genauigkeit angeben.
    Wenn du 8 Nachkommstellen möchtest, schreibst du "%.8f".
    RTFM zu printf

    Du kannst das mit sprintf in einen String schreiben und dann von hinten die Nullen eliminieren.



  • SeppJ schrieb:

    Es ist eben unschön, weil man erst ein uninitialisiertes Objekt erzeugt und dieses dann erst noch mittels einer Memberfunktion in einen gebrauchsbereiten Zustand versetzen muss. Dies läuft den Grundprinzipien der objektorientierten Programmierung zuwider.

    Gar nicht. Es beisst sich bloss mit RAII.

    Wenn man das trotzdem macht zeigt man auch, dass man sich nicht richtig mit den Standardfunktionen und mit gutem Stil auskennt.

    Wenn man sich über solche Kleinigkeiten aufregt, zeigt man ...
    Blah.

    Abgesehen davon ist es auch schlichtweg länger zu schreiben. Und gefährlicher, denn man könnte potentiell ein uninitialisiertes Objekt benutzen oder das open kann fehlschlagen, weil der Stream schon an eine andere Datei gebunden sein könnte.

    Man könnte sowieso potentiell ein uninitialisiertes Objekt benutzen, nämlich wenn man vergisst nach dem ctor erstmal zu gucken ob der Stream auch "good" ist.
    C++ Streams werfen nämlich per Default keine Exceptions.


  • Mod

    Ich erläutere nur, was 3.142... meinte



  • SeppJ schrieb:

    Ich erläutere nur, was 3.142... meinte

    Bist du hellsichtig?

    Wenn etwas vom Herrn dreikommavierzehnfuffzehn stammt, und offensichtlich falsch ist, gehe ich eher davon aus, dass er - freundlich formutliert - vorschnell etwas geschrieben hat, was er glaubt zu wissen, aber eben nicht weiss.


  • Mod

    hustbaer schrieb:

    SeppJ schrieb:

    Ich erläutere nur, was 3.142... meinte

    Bist du hellsichtig?

    Wenn etwas vom Herrn dreikommavierzehnfuffzehn stammt, und offensichtlich falsch ist, gehe ich eher davon aus, dass er - freundlich formutliert - vorschnell etwas geschrieben hat, was er glaubt zu wissen, aber eben nicht weiss.

    Naja, direkt falsch ist es aber auch nicht, was er gesagt hat, nur ein bisschen übertrieben. Es ist nur konsequent die in C++ üblichen Methoden wie RAII hier auch zu benutzen, aus den gleichen Gründen warum man sie überall anders auch benutzt.



  • SeppJ schrieb:

    hustbaer schrieb:

    SeppJ schrieb:

    Ich erläutere nur, was 3.142... meinte

    Bist du hellsichtig?

    Wenn etwas vom Herrn dreikommavierzehnfuffzehn stammt, und offensichtlich falsch ist, gehe ich eher davon aus, dass er - freundlich formutliert - vorschnell etwas geschrieben hat, was er glaubt zu wissen, aber eben nicht weiss.

    Naja, direkt falsch ist es aber auch nicht, was er gesagt hat, nur ein bisschen übertrieben.

    Er sagt gibt's nicht, gibt's aber doch. Viel direkter/klarer/eindeutiger falsch kann etwas nicht mehr sein.

    Es ist nur konsequent die in C++ üblichen Methoden wie RAII hier auch zu benutzen, aus den gleichen Gründen warum man sie überall anders auch benutzt.

    Ja. Das ist deine Meinung. Es gibt andere Meinungen. Und vor allem verschwinden durch Meinungen noch lange keine Methoden aus dem Standard.


Anmelden zum Antworten