Summieren von Kommazahlen mit 0 als Ergebnis geht schief



  • Hallo, liebe c++ - Kenner
    Ich bin gerade dabei, mich in die Sprache einzuarbeiten. Bei der Lösung von einer Übungsaufgabe bin ich langsam am Verzweifeln. Die Aufgabe ist super einfach:
    Man soll dem Programm im Vorfeld angeben, wie viele double- Werte man behandelt, dann sie eingeben und dann soll das Programm unter anderem die Summe der Werte berechnen. Es funktioniert ganz gut, so lange ich nicht Zahlen mit Nachkommastellen eingebe und das Ergebnis der Summe nicht 0 ist (sind nur ganze Zahlen im Spiel oder die SUmme ist ungleich 0, funktionert es auch gut).
    Hier der Code:

    #include <iostream>
    using namespace std;
    int main(int argc, const char * argv[]) {
        int n = 0;
        cout << "Geben Sie Anzahl der Werte ein: " << endl;
        cin >> n;
        double x{0}, summe{0};
        for(int i = 0; i < n; i++){
            cout << "Wert "<< i + 1 << ": ";
            cin >> x;
            cout << endl;
            summe += x;
        }
     cout << "Summe: " << summe << endl;
    return 0;
    }
    

    Wenn meine EIngabe so aussieht:
    3
    5.4
    -2.4
    -3

    Dann lautet die Ausgabe:
    Summe: 4.44089e-16
    statt 0... Kann mir bitte jemand von euch erklären, woran das liegt?



  • Das Problem ist, dass Fließkommazahlen zur Basis 2 gebildet werden, nicht zur Basis 10.

    cout << setprecision(17) << 5.4 << '\n';
    5.4000000000000004
    

    Zur Basis 2 kannst du 1/2, 1/4, 1/8 etc alle exakt darstellen (und Summen daraus), aber nicht 0,2 oder 0,4.

    Im "normalen" 10er-System kannst du 1/3 auch nicht exakt als 0,3333333 darstellen (du bräuchtest unendlich viele Ziffern). Irgendwo musst du aufhören. Je nach Größe der Fließkommazahl (float, double) hast du eine bestimmte Anzahl signifikate Ziffern.


  • Mod

    Weder 5.4 noch -2.4 sind das, was du denkst. Dein Computer stellt die Zahlen intern in einem Binärformat dar. Das hat zur Folge, dass nur Zahlen, die sich als Summe eines Vielfachem von Zweierpotenzen (weil Zwei der einzige Primfaktor im Binärsystem ist) darstellen lassen, auch exakt dargestellt werden können (z.B. 1/2 (=1*2^-1), 3/4 (=3*2^-2), usw.). Alles andere ist dann auf den nächsten darstellbaren Wert gerundet.

    5.4 ist 5 + 2*5^-1. Den Primfaktor 5 haben wir im Binärsystem nicht. Bei einem üblichen 64-Bit double wird das zu 5.40000000000000035527136788005. Und -2.4 ähnlich zu etwas, was sich dann mit 5.4 und eben nicht exakt zu 0 weghebt



  • Das liegt an der internen Darstellung von Fließkommazahlen (d.h. bestimmte Zahlen lassen sich nicht wie in der Dezimalschreibweise exakt in das 2er-Zahlensystem übertragen: Gleitkommazahl).

    Falls du die Schreibweise mit dem e nicht kennst: 4.44089e-16 entspricht 4.44089 * 10^-16, d.h. 0.000000000000000444089 (also fast Null ;-).

    Du kannst aber die Ausgabe auf eine bestimmte Anzahl von Stellen festlegen:

    cout << "Summe: " << setprecision(5) << summe << endl;
    

    (dazu noch <iomanip> einbinden)



  • @die_mit_Fragen Darum rechnet man z.B. bei Geldbeträgen in Cent (oder was die Währung her gibt)



  • @wob @SeppJ @Th69 @DirkB Vielen Dank für die schnelle Hilfe!


  • Banned

    This post is deleted!

Log in to reply