unleserliche darstellung bei kontostand über 1 million



  • Guten Tag!

    Ich bin ein Neuling, was das Programmieren mit C++ angeht. Ich habe mir eine Aufgabe lassen, um etwas zu üben. Das Programm soll den Kontostand des Nutzers einlese und bei entsprechender Höhe einen dezidierten Zinssatz anwenden.

    Bei einem hohen Kontostand wird das ergebnis leider als term angezeigt, obwohl ich eine variable mit großem wertebereich gewählt habe. Kann man das ändern? Habe ich einen Fehler gemacht? Oder ist das bei Konsolendarstellungen normal?

    Vielen Danke für jede Hilfe!

    mfG

    #include "stdafx.h"
    #include <iostream>
    using namespace std;
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        long double Kontostand,NeuerKontostand;
        long double hundert=100.00;
        long double einsfuenf=1.50;
    
        cout<<"Geben Sie ihren Kontostand ein!!\n";
        cin>>Kontostand;
    
        if(Kontostand<1000  && Kontostand>0)
        {
            cout<<"Ihr Zinssatz Beträgt 0,5% \n";
            cout<<"Der Zinswert beträgt:" <<Kontostand/100*0.5<<endl;
            cout<<"Euro\n";
            cout<<"Ihr Neuer Kontostand Beträgt: "<<Kontostand+Kontostand/100*0.5<<endl;
            cout<<"Euro \n";
        }
    
        else if(Kontostand>1000 && Kontostand<5000)
        {
            cout<<"Ihr Zinssatz Beträgt 1,0% \n";
            cout<<"Der Zinswert beträgt: "<<Kontostand/100*1.0<<endl;
            cout<<"Euro";
            cout<<"Ihr Neuer Kontostand Beträgt: "<<Kontostand+Kontostand/100*1.0<<endl;
            cout<<"Euro";
        }
    
        else if(Kontostand>5000)
        {
            cout<<"<Ihr Zinssatz Beträgt 1.5% \n";
            cout<<"Der Zinswert beträgt: "<<Kontostand/hundert*einsfuenf<<endl;
            cout<<"Euro";
            cout<<"Ihr Neuer Kontostand Beträgt: "<<Kontostand+Kontostand/hundert*einsfuenf<<endl;
            cout<<"Euro";
        }
        else
        {
            cout<<"ERROR!!!!Der eingegeben Wert ist unbrauchbar \n";
        }
    }
    

  • Mod

    Guck dir dies mal an:
    http://www.cplusplus.com/reference/iostream/manipulators/fixed/

    Außerdem: double ist ein denkbar schlechter Datentyp um damit gequantelte Größen, wie Geld, zu behandeln. Für ein einfaches Übungsprogramm ist das noch ok, aber mach dir mal Gedanken, warum das nicht so gut ist, damit du es, wenn es drauf ankommt, besser machen kannst.



  • Die Antwort haste ja von SeppJ schon, klar die Zahlen richtig angezeigt zu bekommen ist schon schöner, wobei die darstellung aber ja nicht wirklich unleserlich ist. So rechnet man in Mathe oder Physik sogar sehr oft, gerade zwecks den Einheiten. Jedoch wäre bei diesem Fall eine "normale" Darstellung geschickter.

    Lg freeG



  • SeppJ schrieb:

    Außerdem: double ist ein denkbar schlechter Datentyp um damit gequantelte Größen, wie Geld, zu behandeln. Für ein einfaches Übungsprogramm ist das noch ok, aber mach dir mal Gedanken, warum das nicht so gut ist, damit du es, wenn es drauf ankommt, besser machen kannst.

    Warum? Nur mit double kannst Du die Schulden der BRD auf das Cent genau berechnen. longs würden auf 'nem 32-Bit System nur dem Schäuble freuen. Man muß halt daran denken, bei der Ausgabe das Ergebnis auf 2 Nachkommastellen zu runden.

    mfg Martin



  • Abrunden geht doch mit (in c)

    printf("%2.f", x);
    

    wobei 2 die Zahl der stellen hinterm Komma ist...

    oder mit

    cout.precision(Anzahl_der_Nachkommastellen);
    


  • mgaeckler schrieb:

    SeppJ schrieb:

    Außerdem: double ist ein denkbar schlechter Datentyp um damit gequantelte Größen, wie Geld, zu behandeln. Für ein einfaches Übungsprogramm ist das noch ok, aber mach dir mal Gedanken, warum das nicht so gut ist, damit du es, wenn es drauf ankommt, besser machen kannst.

    Warum? Nur mit double kannst Du die Schulden der BRD auf das Cent genau berechnen. longs würden auf 'nem 32-Bit System nur dem Schäuble freuen. Man muß halt daran denken, bei der Ausgabe das Ergebnis auf 2 Nachkommastellen zu runden.

    mfg Martin

    Das ist Quark. Die Mantisse ist nach IEEE754 bei double genau 52-Bit lang. Du wirst also bei ganzen Zahlen, die betraglich größer als 2^52 sind, mit Rundungsfehlern zu kämpfen haben. So ist etwa 3^52 so nicht darstellbar. Von Cent's brauchen wir da nicht mal reden. Das long nicht das Allheilmittel ist, das dürfte klar sein, aber double erst recht nicht.



  • Hallo mgaeckler,

    <Verschwörungstheorie>
    Ich habe mal gehört, die Banken benutzen zum runden auf zwei Stellen nur die 4 Stellen hinter dem Komma. Die weiter rechts stehenden Stellen werden auf 0 gesetzt und der vorher enthaltene Wert auf das Bankeigene Konto gebucht.
    </Verschwörungstheorie>

    Wenn das so wäre, dann kommen bei mehreren Tausend Buchungen pro Tag auch schon ganz schöne Summen zusammen 🙄

    Herzliche Grüsse
    Walter



  • Hacker schrieb:

    Abrunden geht doch mit (in c)wobei 2 die Zahl der stellen hinterm Komma ist...

    Wir sind hier im C++-Forum. Und in C++ geht das mit std::floor , std::ceil und entsprechenden Multiplikationen für die Anzahl gerundete Stellen:

    void Runden(float& Wert, unsigned short int Nachkommastellen)
    {
      Wert *= std::pow(10, Nachkommastellen);
      Wert = Wert - std::floor(Wert) > 0.5f ? std::ceil(Wert) : std::floor(Wert);
      Wert *= 1.0f / std::pow(10, Nachkommastellen);
    }
    

    Beweis



  • bmario schrieb:

    Das ist Quark. Die Mantisse ist nach IEEE754 bei double genau 52-Bit lang. Du wirst also bei ganzen Zahlen, die betraglich größer als 2^52 sind, mit Rundungsfehlern zu kämpfen haben. So ist etwa 3^52 so nicht darstellbar. Von Cent's brauchen wir da nicht mal reden. Das long nicht das Allheilmittel ist, das dürfte klar sein, aber double erst recht nicht.

    2^52 ist in etwa 4*10^15. Mit Vorzeichen reicht das, um etwa 20 Bilionen Euro auf das Cent genau zu berechnen. Ich schrieb von der BRD nicht von den USA. Obama wird schon ein 64-Bit System brauchen.

    mfg Martin


  • Mod

    mgaeckler schrieb:

    2^52 ist in etwa 4*10^15. Mit Vorzeichen reicht das, um etwa 20 Bilionen Euro auf das Cent genau zu berechnen. Ich schrieb von der BRD nicht von den USA. Obama wird schon ein 64-Bit System brauchen.

    Jetzt verstehe ich die amerikanische Politik! Die spekulieren auf einen Überlauf im Bankencomputer! Wenn sie ganz großes Glück haben, benutzt die Bank einen signed Datentyp, dann bekommen sie sogar noch Geld zurück.



  • mgaeckler schrieb:

    Warum? Nur mit double kannst Du die Schulden der BRD auf das Cent genau berechnen.

    Mit double kann man gar nix auf den Cent genau berechnen. Probier zB mal:

    #include <iostream>
    #include <iomanip>
    
    using namespace std;
    
    int main()
    {
    	double betrag = 0.1;
    
    	for(int i = 0; i < 9; ++i)
    		betrag += 0.1;
    
    	cout << setprecision(20) << fixed << betrag;
    }
    

    und Du wirst sehen, dass double Rundungsfehler aufweist. Wenn man sich nun eine Vielzahl von Addition/Subtraktionsoperationen vorstellt, wo die (Zwischen)ergebnisse möglicherweise noch multipliziert/dividiert werden, dann erkennt man, dass man unter dem Strich erhebliche Abweichungen von den tatsächlichen Ergebnissen erhält.

    Deshalb nochmal:

    SeppJ schrieb:

    double ist ein denkbar schlechter Datentyp um damit gequantelte Größen, wie Geld, zu behandeln.



  • Belli schrieb:

    mgaeckler schrieb:

    Warum? Nur mit double kannst Du die Schulden der BRD auf das Cent genau berechnen.

    Mit double kann man gar nix auf den Cent genau berechnen. Probier zB mal:

    #include <iostream>
    #include <iomanip>
    
    using namespace std;
    
    int main()
    {
    	double betrag = 0.1;
    	
    	for(int i = 0; i < 9; ++i)
    		betrag += 0.1;
    		
    	cout << setprecision(20) << fixed << betrag;
    }
    

    und Du wirst sehen, dass double Rundungsfehler aufweist. Wenn man sich nun eine Vielzahl von Addition/Subtraktionsoperationen vorstellt, wo die (Zwischen)ergebnisse möglicherweise noch multipliziert/dividiert werden, dann erkennt man, dass man unter dem Strich erhebliche Abweichungen von den tatsächlichen Ergebnissen erhält.

    Deshalb nochmal:

    SeppJ schrieb:

    double ist ein denkbar schlechter Datentyp um damit gequantelte Größen, wie Geld, zu behandeln.

    Ja, schon recht. Man muß aber nicht päpstlicher als der Papst sein:

    0.1 + 0.1 = 0.200000000000000011

    Da mussen schon einige Rechnungen zusammen kommen, bis sich dieser Fehler in Cent auswirkt.

    Ich sag jetzt einfach mal so: Wenn es um finazmathematische Berechnungen mit einigermassen überschaubaren Beträgen und Zeiträumen geht, kann man ohne Probleme den Typ double benutzen.

    Wer aber auf den Cent genau ausrechnen will, wieviel Zinsen ein Neandertaler heute bezahlen muß, der sich vor 100000 Jahren ein Mamut geliehen hat, der sollte vieleicht was anderes benutzen.

    mfg Martin



  • Ich sag jetzt einfach mal so: Wenn es um finazmathematische Berechnungen mit einigermassen überschaubaren Beträgen und Zeiträumen geht, kann man ohne Probleme den Typ double benutzen.

    Mit dem Argument ist aber auch ein long gross genug. Warum also den fehlerhaften double nehmen?


  • Mod

    mgaeckler schrieb:

    Da mussen schon einige Rechnungen zusammen kommen, bis sich dieser Fehler in Cent auswirkt.

    Ich sag jetzt einfach mal so: Wenn es um finazmathematische Berechnungen mit einigermassen überschaubaren Beträgen und Zeiträumen geht, kann man ohne Probleme den Typ double benutzen.

    Wer aber auf den Cent genau ausrechnen will, wieviel Zinsen ein Neandertaler heute bezahlen muß, der sich vor 100000 Jahren ein Mamut geliehen hat, der sollte vieleicht was anderes benutzen.

    Das ist ein ganz gefährlicher und kurzsichtiger Rat, den du da gibst. Man muss kein Numeriker sein, um einfache Rechenbeispiele zu finden, in denen der relative Fehler explodiert. Eine einfache Subtraktion zweier ähnlicher Werte genügt. Und wenn man das Ergebnis noch multipliziert oder exponenziert, dann wird auch der absolute Fehler groß.



  • Ne, ich habe mir vor (wirklich vielen) Jahren mal eine Anwendung zur Kontoverwaltung geschrieben. Dort habe ich aus Unwissenheit double für die Betragsspeicherung gewählt.

    Da kommen im Jahr sicher keine 1000 Datensätze zusammen. Wenn ich da einfach alle Buchungen addiere - wobei es natürlich jede Menge Buchungen mit negativem Vorzeichen gibt - dann habe ich ab und zu eine Abweichung von 1 Ct. gegenüber dem tatsächlichen Kontostand.
    Wenn ein paar Wochen später weitere Buchungen hinzugekommen sind, gleicht sich das häufig wieder aus.
    Aber: Es ist eine Abweichung spürbar, und zwar ohne dass Multiplikationen/Divisionen zur Anwendung kommen.

    Also für Anwendungen mit etwas ernsthafteren Ambitionen ist das wirklich nicht zu empfehlen.

    Mir selbst ging das nach einer Weile so auf den Wecker, dass ich die Doubles nun vor der Addition nach int konvertiere, addiere, und dann für die Bildschirmdarstellung wieder ein Komma dazwischen fummel.

    Viel problematischer für mich war beim ersten Auftreten, dass ich mir das gar nicht erklären konnte, da mir diese Problematik überhaupt nicht bekannt war, deshalb finde ich es okay, Programmierpadawane so früh wie möglich darauf hinzuweisen und das auch nicht zu verharmlosen.



  • Welcher Datentyp wäre dann eurer Meinung nach der geeignetste?


  • Mod

    freddixx schrieb:

    Welcher Datentyp wäre dann eurer Meinung nach der geeignetste?

    Wenn du es mit Zuckerguss haben möchtest: Schreib dir eine Geldklasse. Das wäre in C++ (oder allgemein der objektorientierten Programmierung) die übliche Herangehensweise.

    Wenn du bloß schnell ein Beispielprogramm zusammenhacken möchtest: Ein ganzzahgliger Datentyp wie int bewahrt dich erst einmal vor dem schlimmsten, denn Geld kommt schließlich auch immer in ganzen Einheiten. Dann rechnest du eben in Cent oder Zehntelcents ansstatt in Euros.



  • Jockelx schrieb:

    Ich sag jetzt einfach mal so: Wenn es um finazmathematische Berechnungen mit einigermassen überschaubaren Beträgen und Zeiträumen geht, kann man ohne Probleme den Typ double benutzen.

    Mit dem Argument ist aber auch ein long gross genug. Warum also den fehlerhaften double nehmen?

    long hat auf 32-Bitsystemen einen Wertebereich von ca +/-2000000000 in Euro sind das gerade mal 20 Milionen. Das erscheint mir dann doch zu wenig auch wenn es für die meisten (eh irgendwelche Spekulationen aufkommen: Auch für mein Unternehmen) ausreicht.

    Man muß einfach sich überlegen, welche Datentypen-/strukturen welche Vor- und Nachteile haben. Für eine Ganzzahlrechnung, wie auch immer die ausschaut, spricht, daß man sich nicht um Rundungsfehler kümmern muß. Dagegen spricht aber, daß diese nicht so flexibel sind. Man muß einmal die Semantik definieren (ist das Cent, zehntel oder gar hundertstel Cent) und diese durch das ganze Programm durchziehen. Was aber ist, wenn der Gesetzgeber plötzlich anfängt, da herum zu spielen, dann kann es einem passieren, daß hier plötzlich alles über den Haufen geworfen werden muß. Der Wartungsaufwand kann dann echt übel werden.

    mfg Martin



  • Belli schrieb:

    Ne, ich habe mir vor (wirklich vielen) Jahren mal eine Anwendung zur Kontoverwaltung geschrieben. Dort habe ich aus Unwissenheit double für die Betragsspeicherung gewählt.

    Da kommen im Jahr sicher keine 1000 Datensätze zusammen. Wenn ich da einfach alle Buchungen addiere - wobei es natürlich jede Menge Buchungen mit negativem Vorzeichen gibt - dann habe ich ab und zu eine Abweichung von 1 Ct. gegenüber dem tatsächlichen Kontostand.
    Wenn ein paar Wochen später weitere Buchungen hinzugekommen sind, gleicht sich das häufig wieder aus.
    Aber: Es ist eine Abweichung spürbar, und zwar ohne dass Multiplikationen/Divisionen zur Anwendung kommen.

    Also für Anwendungen mit etwas ernsthafteren Ambitionen ist das wirklich nicht zu empfehlen.

    Mir selbst ging das nach einer Weile so auf den Wecker, dass ich die Doubles nun vor der Addition nach int konvertiere, addiere, und dann für die Bildschirmdarstellung wieder ein Komma dazwischen fummel.

    Viel problematischer für mich war beim ersten Auftreten, dass ich mir das gar nicht erklären konnte, da mir diese Problematik überhaupt nicht bekannt war, deshalb finde ich es okay, Programmierpadawane so früh wie möglich darauf hinzuweisen und das auch nicht zu verharmlosen.

    Hallo,

    eine solche Erfahrung habe ich bisher nicht gemacht und das wäre echt übel, wenn dem so wäre. Dann müsste ich tatsächlich eine Aussage zurückziehen. Ich kann mir allerdings nicht vorstellen, daß es an dem Datentyp double liegt, werde aber mal versuchen, ob ich ein Testprogramm schreiben kann, mit dem das nachvollzogen werden kann. Bis dahin werde ich allerdings meine Äusserung nicht wiederholen.

    mfg Martin



  • @mgaeckler:
    Deswegen ja eine Geldklasse. Ein simpler Wrapper um einen int64 (reicht für über 90 Billiarden €, also vermutlich zumindest für das nächste halbe Jahrtausend) mit hübscher Ausgaberoutine und ein paar Konvertierungsfunktionen. Also mitsamt Testen in vielleicht 1/2h bis 1h geschrieben. Alternativ in 5min aus dem Netz geladen. Und schon hat man (vorläufig) nie mehr Probleme weder mit Wertebereich noch mit Genauigkeit. Und wenn der Gesetzgeber den Zehntelcent einführt, ändert man eine Klasse und eine Ausgaberoutine. Wer weiß, wie viele Stellen man mit double hätte, an denen manuell auf 2 Nachkommastellen gerundet wird?


Log in to reply