Float Werte in CSV schreiben



  • Hallo Leute,

    ich versuche float Werte korrekt in eine CSV zu schreiben. Das klappt aber leider nicht. Die Werte, die abgespeichert werden, stimmen nicht, bzw. werden gerundet.
    Ich brauche die exakten float Zahlen. Woran liegt das? Danke euch.

    #include <iostream>
    #include <vector>
    
    int main()
    {
    	std::ofstream myfile;
    
    	float variable1 = 1234.12f;
    	float variable2 = 123456.1234f;
    	float variable3 = 12345678.123456f;
    	float variable4 = 12345678.12345678f;
    
    	myfile.open("test.csv");
    
    	myfile << variable1 << ";";
    	myfile << variable2 << ";";
    	myfile << variable3 << ";";
    	myfile << variable4 << ";";
    
    	myfile.close();
    
            system("pause");
    }
    


  • Keine der Zahlen kann als IEEE-754 float genau dargestellt werden.



  • Mit double gleiches Spiel. Okay dann formuliere ich anders. Wie kann man Gleitkommazahlen korrekt in CSV Dateien schreiben?



  • Das Problem ist nicht das Schreiben. Das Problem ist daß schon alleine die Darstellung als FLIESSkommazahl im Binärsystem nicht funktioniert. Wenn Du wirklich solche Genauigkeit brauchst dann nimm eine Arbritrary-Precision Library.
    Womit rechnest Du denn da? Geld?



  • Finance Daten ja. Hast du ein simples Code Beispiel? danke dir



  • Dann vergiss Fließkommazahlen. Rechne mit ganzen Zahlen in hundertstel oder tausendstel cents. Fürs Schreiben kannst Du ja das Komma setzen wie Du lustig bist.

    Intel® Decimal Floating-Point Math Library evtl.



  • Nein, das ist nicht der Sinn der Sache. Die Anforderung ist es Gleitkommazahlen in CSV Dateien zu schreiben. Die Zahlen sind sehr vielfältig und haben vor und nach der Kommastelle noch vor dem Schreibvorgang verschiedene Größen. Das muss automatisiert ohne Rumgebastel erfolgen.



  • Was heißt "Rumgebastel"? Deine Methode ist zum Rechnen mit Geldbeträgen nicht geeignet. Auch nicht vor dem Schreiben. Wenn Du auf Deine floats und doubles bestehst dann ist da eben die Ungenauigkeit. Da kannst Du Dich auf den Kopf stellen. Das wird nicht anders. Du hast jetzt halt die Möglichkeit es zu machen wie der Rest der Welt oder Dich weiter über etwas Unveränderliches aufregen.



  • Was Swordfish Dir sagen will, kannst Du selbst mit folgendem kleinen Beispiel ausprobieren:

    #include <iostream>
    
    using namespace std;
    
    int main()
    {
       const float ziel = 1.0;
       const float addWert = 0.1;
       
       float var = 0.0;
       
       for(int i = 0; i < 10; ++i)
          var += addWert;   
    
       cout << "Ziel: " << ziel << '\n';
       cout << "Var:  " << var << '\n';
       
       if(ziel == var)
          cout << "Ziel ist gleich Var";
       else
          cout << "Ziel ist ungleich Var";
          
       cout << '\n';   
    }
    


  • Gut, ich dachte das geht direkt ohne multiplizieren. Vielleicht hat ja noch jemand eine Idee, wie man direkt Gleitkommazahlen in CSVs schreiben kann, ohne voher zu shiften.

    Hat man bei txt Dateien das gleiche Problem?



  • @des1re10 sagte in Float Werte in CSV schreiben:

    Hat man bei txt Dateien das gleiche Problem?

    Nochmals: das hat nichts, NICHTS (!) mit CSV zu tun, sondern einfach damit, dass Fließkommazahlen nicht die Genauigkeit haben! Das ist so ähnlich, als würdest du fordern, 1/3 = 0.33333 exakt zu schreiben. Auch das geht nicht, irgendwo musst du abschneiden. Du könntest beim Schreiben runden, aber auch dann gilt, was @Swordfish gesagt hat.

    Ob du nun TXT oder CSV nimmst, ist irrelevant.



  • double hat eine sehr hohe Genauigkeit. Bis ins Unendliche sollten die Zahlen ebenfalls nicht ausgeschrieben werden. War auch nicht verlangt. Ging primär um die korrekte Kommasetzung ohne Konvertierung vorher. Dachte das wäre möglich. Gut dann werde ich multiplizieren und anschließend dividieren.

    Danke euch!



  • @des1re10 sagte in Float Werte in CSV schreiben:

    double hat eine sehr hohe Genauigkeit. Bis ins Unendliche sollten die Zahlen ebenfalls nicht ausgeschrieben werden.

    Du verstehst immer noch nicht. Genauso wie im Dezimalsystem (oben das Beispiel von @wob mit 1/3 = 0.33333333333333333333333333...) gibt es im Dualsystem Zahlen die zwar im Dezimalsystem darstellbar sind, jedoch nicht im Dualsystem. Das ist schonmal das erste Problem an dem du nichts ändern kannst. Geld? Nix float, nix double. Integer (int, long, long long, sonstwas), spezialisierte Libraries die einen Typ für Geld anbieten (die machen intern auch nichts anderes) oder eben spezielle Libraries für Arbitrary Precision wie oben schon verlinkt.

    Das da:

    @des1re10 sagte in Float Werte in CSV schreiben:

    float variable3 = 12345678.123456f;
    

    Der Wert der da im Dezimalsystem in Deinem Source-File steht ist ja gut und schön. Aber sobald der in einem float oder double gespeichert wird ist es ein anderer weil der der in Deinem Source-File so schön steht nicht darstellbar ist. Das Problem hast Du nicht erst bei der Ausgabe sondern von Anfang an.

    Is floating point math broken?
    What every Compiuter Scientist Should Know About Floating-Point Arithmetic (pdf)



  • @des1re10: Unter IEEE-754 Floating Point Converter kannst du das selber testen.
    Z.B. für float variable1 = 1234.12f; ergibt die interne Repräsentation schon 1234.1199951171875 , d.h. die Ungenauigkeit beträgt -0.0000048828125.
    Und bei deinen beiden letzten Variablen 3+4 fällt sogar der komplette Nachkommaanteil weg (d.h. es wird nur 12345678 gespeichert), da ein float nur ca. 7-8 Dezimalziffern präzise speichern kann (für double sind es 15-17).
    Bei größeren Zahlen, wie z.B. 123456789 sind dann sogar die letzten Vorkommastellen ungenau (hier 123456792), und je länger die Zahlen werden, desto ungenauer wird es - s.a. Gleitkommazahl.


Log in to reply