Wie funktioniert Konvertierung von double zu int?



  • Ja klar. Wenn man (ich) von Anfang an um die Problematik gewußt hätte, hätte man die Werte von vornherein als int - Werte bearbeitet und nur für die Ausgabe/Anzeige ein Komma an die richtige Stelle gesetzt.
    Aber ich habe hier eine Anwendung, die fast 20 Jahre alt ist; von den Rundungsproblemen wurde ich irgendwann viel später überrascht, wahrscheinlich ist das ein Problem, mit dem Programmieranfänger überhaupt nicht rechnen ...



  • Hallo Belli,

    willkommen im Club!

    Fliesskommazahlen (float, double, ...) sind nun einmal viel genauer als Ganzzahlen (int, ...). Man setzt sie deshalb auch vor allem in technischen und wissenschaftlichen Berechnungen ein. Bei Geldbeträgen - wie du gesehen hast - kann es unschöne Unstimmigkeiten geben. Vielleicht musst du mit der übernommenen Datei und den vorhandenen double-Werten keinen grossen Aufwand treiben. Dazu solltest du aber mehr über das die Datei auswertende Programm mitteilen.

    Du hast die Problematik erkannt und bist damit über den Anfänger hinaus gekommen. Der Rest ist 'Softwarepflege' versus 'Neuprogrammierung'. Ein 20 Jahres alte fremdes Programm anpassen zu wollen, ist nicht unbedingt ratsam und muss deswegen im Aufwand sehr sorgfältig durchdacht sein.



  • berniebutt schrieb:

    Hallo Belli,
    Fliesskommazahlen (float, double, ...) sind nun einmal viel genauer als Ganzzahlen (int, ...)...

    Ähmm nein. Fliesskommazahlen sind eben nicht genauer.



  • Fliesskommazahlen (float, double, ...) sind nun einmal viel genauer als Ganzzahlen (int, ...).

    nö. ganzzahlen sind genau(natürlich nur in ihrem wertebereich). fließkommazahlen sind die, die ungenau sind...



  • unskilled schrieb:

    nö. ganzzahlen sind genau(natürlich nur in ihrem wertebereich). fließkommazahlen sind die, die ungenau sind...

    Und eben in dem Wertebereich von Ganzzahlen - also z.B. zwischen 1 und 2 - sind Fliesskommazahlen sehr genau, sonst bräuchte man sie nicht!

    Beispiel:
    - ganzahlige Division 3 / 2 liefert 1
    - Flieskommadivision 3. / 2. liefert 1.5

    Was ist nun genau und was ungenau?

    Aber das lernt man schon im Kindergarten mit der einfachen Aufgabe 3 Äpfel gerecht auf 2 Kinder aufzuteilen. Man braucht dafür ein Messer zum Teilen und trifft es damit nie präzise genau, aber immerhin besser als jedem Kind 1 Apfel zu geben und den 3. Apfel selbst zu nehmen. :p



  • berniebutt schrieb:

    unskilled schrieb:

    nö. ganzzahlen sind genau(natürlich nur in ihrem wertebereich). fließkommazahlen sind die, die ungenau sind...

    Und eben in dem Wertebereich von Ganzzahlen - also z.B. zwischen 1 und 2 - sind Fliesskommazahlen sehr genau, sonst bräuchte man sie nicht!

    Blödsinn. Wenn alle Zahlen zwischen 1 und 2 sind, merkt man sich intern vielleicht nen Offset von 1 und den betragsmäßig größten Exponenten, sodass der Wertebereich der Integer verkleinert durch den Exponenten das Intervall noch ganz überdeckt, wenn man denn die höchste Genauigkeit mit einfachen Mitteln haben möchte.



  • berniebutt schrieb:

    unskilled schrieb:

    nö. ganzzahlen sind genau(natürlich nur in ihrem wertebereich). fließkommazahlen sind die, die ungenau sind...

    Und eben in dem Wertebereich von Ganzzahlen - also z.B. zwischen 1 und 2 - sind Fliesskommazahlen sehr genau, sonst bräuchte man sie nicht!

    Sie sind in keinster Weise "genau". Integer haben exakte Werte und solange man im Wertebereich bleibt, wird auch jede Addition ein exaktes Ergebnis liefern. Letzteres ist für Fließkommazahlen eben schon nicht gegeben. Auch ein grund dafür, warum man wenn man viele Fließkommazahlen addieren will, sie vorher sortieren sollte und beim addieren mit den Kleinsten beginnt, so das die Rechenverluste möglichst gering sind.



  • Michael E. schrieb:

    Blödsinn. Wenn alle Zahlen zwischen 1 und 2 sind, merkt man sich intern vielleicht nen Offset von 1 und den betragsmäßig größten Exponenten, sodass der Wertebereich der Integer verkleinert durch den Exponenten das Intervall noch ganz überdeckt, wenn man denn die höchste Genauigkeit mit einfachen Mitteln haben möchte.

    Wer soll das verstehen mit deiner Float-Arithmetik für integer und dem Gebrauch von Offsets? 😕 Ich nicht!!! 😞 Wozu kennen denn alle Compiler seit Olims Zeiten verschiedene Datentypen wie integer und float???

    Hat jedoch wenig mit Programmierung oder C++ zu tun, sondern eher mit dem Grundlagenwissen der Mathematik. Lernt man nach dem Kindergarten in der Schule!
    Ich programmiere grundsätzlich zuerst im Kopf und wähle danach die geeigneten Methoden aus. Hat mir bisher nicht geschadet. Offsets kannte ich nur aus 8- oder 16-bit-Zeiten die für Adressierung von Speicherbereichen 😡

    @asc: Ja, Integers sind exakt auf eben ganzzahlige Werte. Alles dazwischen geht schlicht verloren, was möglicherweise fatale Wirkung haben kann. Da soll mal jemand bei einer Bank die abgeschnittenen Zinserträge der Kunden zu seinem Gunsten aufaddiert haben - kam richtig was raus - ist aber aufgefallen!



  • berniebutt schrieb:

    Wer soll das verstehen mit deiner Float-Arithmetik für integer und dem Gebrauch von Offsets? 😕 Ich nicht!!! 😞

    Das hast du doch selbst vorgeschlagen:

    Alternativen:
    1. Mit longint in Cent rechnen

    Wozu kennen denn alle Compiler seit Olims Zeiten verschiedene Datentypen wie integer und float???

    Weil es auch Anwendungsbereiche für Fließkommazahlen gibt. Beim Rechnen mit Währungen nimmt man aber besser Festkommazahlen. Diese simuliert man in C++ eben am einfachsten, indem man sich immer nen Exponenten denkt (-> Cents statt Euro).

    Hat jedoch wenig mit Programmierung oder C++ zu tun, sondern eher mit dem Grundlagenwissen der Mathematik. Lernt man nach dem Kindergarten in der Schule!

    Was hat wenig mit Programmierung zu tun und was lernt man direkt in der Schule? Deine Beiträge enthalten leider oft zusammenhangslose Sätze, mit denen ich nichts anfangen kann.

    Offsets kannte ich nur aus 8- oder 16-bit-Zeiten die für Adressierung von Speicherbereichen 😡

    Kein Grund böse zu werden.



  • berniebutt schrieb:

    @asc: Ja, Integers sind exakt auf eben ganzzahlige Werte. Alles dazwischen geht schlicht verloren, was möglicherweise fatale Wirkung haben kann.

    Wie exakt sind denn deiner Meinung nach Fließkommazahlen?

    Alles dazwischen geht schlicht verloren

    Bei Fließkommazahlen auch. Ich wüsste auch nicht, wie man es sonst anstellen sollte 😉

    Edit:

    Und eben in dem Wertebereich von Ganzzahlen - also z.B. zwischen 1 und 2 - sind Fliesskommazahlen sehr genau, sonst bräuchte man sie nicht!

    Rechne mal

    float(int_max)-1
    

    wenn Float und Int gleich viel Speicher belegen.



  • @An Alle: Mannomann - wenn wir Oldie-Programmierer uns mit den seinerzeit schlechteren Compilern um solchen Kleinkram gekümmert hätten, wäre kein Programm gelaufen. Was macht ihr da heute? 😕

    Ein Programm muss zuverlässig laufen. Möglichst mit dem geringsten Aufwand zur Programmierung, nicht viel Laufzeit und Speicher verbraten - und sonst nichts! :p Bin ich hier mit meiner Meinung allein?

    @Fragesteller: Du bist auf dem richtigen Weg.



  • berniebutt schrieb:

    Ein Programm muss zuverlässig laufen.

    Genau da hängts doch mit double 🙄



  • Aaaalso:
    Die Anwendung ist von mir selbst geschrieben worden - damals in C. Ein einigermassen aufwendiges Konsolenprogramm mit Eingabemasken und so weiter. Da die Windows-Konsole nicht mehr 100%ig der damaligen DOS-Konsole entspricht, ich aber beim Jahrtausendwechsel noch mal 'dran musste', sind mittlerweile einige wenige Dinge drin, die sich ein paar Vorteile von C++ zu Nutze machen - es ist aber bei weitem kein C++ - Programm.
    In der Zwischenzeit habe ich mal begonnen, eine Klasse für BCD-Zahlen zu schreiben, beim Dividieren habe ich's glaube ich erst Mal einstellen müssen ... aber in meiner Anwendung würde subtrahieren und addieren auch genügen. Da ich aber nur zwei Nachkommastellen habe, genügt mir eine Konvertierung in Integer vor Addition/Subtraktion; das ist auf jeden Fall um Längen einfacher, als nun in allen relevanten Programmteilen den Datentyp auszutauschen. Naja - eigentlich war meine Ursprungsfrage ja, wie wird (vom Compiler) die Umwandlung durchgeführt, da es ja den Anschein macht, daß eben nicht einfach abgeschnitten wird, sondern gerundet, was für mich die zweite Überraschung (nach den Genauigkeitsproblemen der Fließkommazahlen vor ein paar Jahren) ist.
    Ja - und ich habe eben gelernt, daß es weniger umständlich geht, als ich es angegangen bin (Stichwort: Addition eines geeigneten Epsilon-Wertes).



  • berniebutt schrieb:

    @An Alle: Mannomann - wenn wir Oldie-Programmierer uns mit den seinerzeit schlechteren Compilern um solchen Kleinkram gekümmert hätten, wäre kein Programm gelaufen. Was macht ihr da heute? 😕

    Ich nehm absichtlich ein einfaches Beispiel, das unter MSVC 2010 massiv demonstriert was float & double für Probleme haben (Je nach Typgenauigkeit der Plattform ist dies anzupassen).

    Und ja, dies war schon praxisrelevant und hat Geldbeträge in einer Anwendung verfälscht (Wo es um die Aufteilung von Summen über Kostenstellen ging, damals soviel ich noch in Erinnerung habe mit double).

    #include <iostream>
    #include <iomanip>
    
    int main()
    {
    	float f = 10000000;
    	float f2 = 20000000;
    	for(int i=0; i<10000000; ++i)
    		f += 1;
    	std::cout << std::fixed << f << std::endl << f2;
    }
    

    Wenn ich Genauigkeit brauche wähle ich sicherlich weder float noch double. Für Geldsummen, je nach Rechenregeln (z.B. erinnere ich mich entfernt noch an ein Dokument für Währungsumrechnungen, Fixkomma mit 2 Nachkommastellen für Endsummen und 4 für Berechnungen)...



  • Du könntest im Prinzip auch mit ReadProcessMemory den Wert auslesen. Musst dann halt nur die Mantisse, den Exponent und die Basis einzeln auslesen.



  • asc schrieb:

    Wenn ich Genauigkeit brauche wähle ich sicherlich weder float noch double. Für Geldsummen, je nach Rechenregeln (z.B. erinnere ich mich entfernt noch an ein Dokument für Währungsumrechnungen, Fixkomma mit 2 Nachkommastellen für Endsummen und 4 für Berechnungen)...

    Wenn ich Genauigkeit auch in den Nachkommastellen brauche wähle ich float oder double, sonst habe ich oft Murks. Es geht aber um Geldbeträge - den zehntel Cent gibt es nur an der Zapfsäule der Tanke, nicht an der Kasse!

    Der Fragesteller hat in seinem alten Programm für Geldbeträge bereits double gewählt. Eine Umstellung auf long int wird sicher aufwendig und ist daher nicht zu empfehlen.

    Man kann für Geldbeträge durchaus double einsetzen. Z.B. mit dem was du da mal gelesen hast und auch mir schwach in Erinnerung ist. Für die Zielsetzung besser erscheint mir der Einsatz der von mir vorgeschlagenen Funktionen runden() und dtoa(). Ich bin damit stets recht gut zurecht gekommen und vermeide so die Unstimmigkeiten mit double, wo das relevant ist.

    Egal, ob long int oder double: Bei Berechungen mit Geldbeträgen muss man genau wissen, was man tut!



  • Was mach ich nun mit mein Programm, dass 33 Cent verschluckt?

    int main() { 	
    	double values = 12.04 + 11.99 + 123.10 + 9000.01 + 900000.19;
    
    	cout << values << endl;
    	cin.get();
    }
    

  • Mod

    berniebutt schrieb:

    Wenn ich Genauigkeit auch in den Nachkommastellen brauche wähle ich float oder double, sonst habe ich oft Murks. Es geht aber um Geldbeträge - den zehntel Cent gibt es nur an der Zapfsäule der Tanke, nicht an der Kasse!

    Nein. Deine Vorstellungen vom Einsatzgebiet von Fließkommazahlen sind falsch. Es geht bei double vs. int nicht um Komma oder kein Komma. Es geht um diskret vs. kontinuierlich*.

    Rechnen mit Geld ist ganz klar ein diskretes Problem. Der Einsatz von Fließkommazahlen in der wissenschaftlichen Rechnung hat damit zu tun, dass die dort vorliegenden Probleme häufig Kontinuumsmechanik sind. Das hat überhaupt nichts mit Genauigkeit zu tun!

    *: Natürlich sind Fließkommazahlen keine perfekte Repräsentation des Kontinuums - dies ist auf einem Digitalrechner unmöglich. Aber es ist eine gute Näherung.



  • SeppJ schrieb:

    Nein. Deine Vorstellungen vom Einsatzgebiet von Fließkommazahlen sind falsch. Es geht bei double vs. int nicht um Komma oder kein Komma. Es geht um diskret vs. kontinuierlich*.

    In der Sprache der Mathematiker: natürliche Zahlen (0,1,2,3, ...) und reelle Zahlen. Den Unterschied lernt man doch schon in der Schule oder heute nicht mehr? Die reellen Zahlen heissen in der Schule manchmal Bruchzahlen, wenn ich mich recht erinnere.

    Wie könnte jemand als Programmierer mit seiner Arbeit Geld verdienen, wenn er nicht über die grundlegenden Datentypen, deren Einsatz, und der wie bei Geldbeträgen vorhandenen Problematik nicht bescheid wüsste? 😕

    Mach mal eine technische oder wissenschaftlich Berechnung mit int statt float. Da fliegst du schnell allein mit dem darstellbaren Wertebereich auf die Schnauze! Ach so, was machst du bei Zins- oder Mehrwertsteuer-Berechnungen mit den Anteilen hinter dem Cent? Wegschmeissen oder geschickt in die eigene Tasche stecken?



  • Sorry berniebutt, aber du liegst in einigen Dingen falsch.

    Die Bruchzahlen heißen auch rationale Zahlen und sind nur ein Teil der reellen Zahlen (PI und E und unendlich weitere Zahlen lassen sich nicht als Bruch darstellen). (Soviel zur Schulbildung -)

    Und wenn man Zins oder Mehrwertberechnung mit höherer Genauigkeit benutzen will, dann sollte man dafür dann eben eine entsprechende Fixkommazahl mit größerem Nachkommaanteil wählen (aber Fließkommazahlen sind vom Namen her schon ungeeignet, da die Genauigkeit abhängig von der Größe der Zahl ist, d.h. "1Mio. und 15 Cent" lassen sich mit 7 Dezimalstellen Genauigkeit (bei einem 4 Byte float) einfach nicht mehr darstellen).

    Für wirklich exakte Berechnungen im wiss. und techn. Bereich (d.h. große Zahlen sowie hohe Genauigkeit im Nachkommaanteil) benötigt man dann entsprechend eigene Datentypen (mittels Fixkommazahlen auf der Basis von 'int').

    P.S. Noch ein Beispiel was gegen Fließkommazahlen spricht ist folgendes:

    float x = 0;
    while(++x)
      cout << x << endl;
    

    Wunder dich dann nicht, daß du keine Zahlen größer als ca. 16 Mio angezeigt bekommst...

    Oder teste es einfach mal so aus:

    float x = 0;
    while(x != x+1)
    {
      ++x;
    }
    
    cout << x << endl;
    

    Wetten, daß das keine Endlosschleife ist?
    (mit 'double' dauert es halt etwas länger...)


Anmelden zum Antworten