Henry: Addition Summierung von Zahlen seltsame Fehler Kommastellen

Hallo,

Ich nutze eine Schleife um Beträge auszuwerten, funktioniert auch soweit, aber unerwartet viele Nachkommastellen.

928.15 + 2.9 = 931.05
931.05 + 2.9 = 933.95
933.95 + 2.9 = 936.85
936.85 + 2.9 = 939.75
939.75 + 2.9 = 942.65
942.65 + 2.9 = 945.55
945.55 + 2.9 = 948.45
948.45 + 2.9 = 951.35
951.35 + 2.9 = 954.24999999999
954.24999999999 + 2.9 = 957.14999999999
957.14999999999 + 2.9 = 960.04999999999
960.04999999999 + 2.9 = 962.94999999999
962.94999999999 + 3 = 965.94999999999
965.94999999999 + 2.9 = 968.84999999999
968.84999999999 + 2.9 = 971.74999999999
971.74999999999 + 2.9 = 974.64999999999
974.64999999999 + 2.9 = 977.54999999999
977.54999999999 + 2.9 = 980.44999999999
980.44999999999 + 2.9 = 983.34999999999
983.34999999999 + 2.9 = 986.24999999999
986.24999999999 + 2.9 = 989.14999999999
989.14999999999 + 2.9 = 992.04999999999
992.04999999999 + 2.9 = 994.94999999999
994.94999999999 + 3 = 997.94999999999
997.94999999999 + 2.9 = 1000.85
1000.85 + 2.9 = 1003.75
1003.75 + 2.9 = 1006.65
1006.65 + 2.9 = 1009.55

Der erste Wert ist immer das Produkt der vorangegangen Aufgabe.

$total += $x;

Warum wird dann urplötzlich aus 951.35 + 2.9 = 954.24999999999 und nicht 954.25? Was übrigens nicht passiert, wenn ich das als Einzelaufgabe ausprobiere. Dass ich das mit zb. round() ändern kann ist klar, aber möchte nur wissen warum das so ist und warum als Einzelaufgabe nicht.

Gruss
Henry

--
Meine Meinung zu DSGVO & Co:
„Principiis obsta. Sero medicina parata, cum mala per longas convaluere moras.“

akzeptierte Antworten

  1. @@Henry

    … unerwartet viele Nachkommastellen.

    FAQ: Wieso habe ich beim Rechnen mit Dezimalzahlen Rechenfehler?

    LLAP 🖖

    --
    „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
    „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

    —Marc-Uwe Kling
    1. Hallo Gunnar,

      FAQ: Wieso habe ich beim Rechnen mit Dezimalzahlen Rechenfehler?

      Sehr informativ, danke.

      Also "Nicht exakt darstellbare Zahlen im Binärsystem". Das bedeutet dann wohl, in der Schleife ist der wahre(im System unsichtbare) Wert im Hintergrund beim Breakpoint ein anderer, als bei einer gleichen(im sichtbaren Bereich) Einzelrechnung.

      Dann vermute ich mal, es ist sinnvoller lange Operationen besser als Ganzwert abzuarbeiten und erst am Ende wieder in einen gebrochenen Wert ändern?

      Gruss
      Henry

      --
      Meine Meinung zu DSGVO & Co:
      „Principiis obsta. Sero medicina parata, cum mala per longas convaluere moras.“
      1. Hallo

        Dann vermute ich mal, es ist sinnvoller lange Operationen besser als Ganzwert abzuarbeiten und erst am Ende wieder in einen gebrochenen Wert ändern?

        Das wird auch in anderen Kontexten empfohlen. Mir war so, das hier mal in Bezug auf Geldbeträge in MySQL gelesen zu haben. Das Problem stellt sich mit Integer-Zahlen nicht, also ja, das ist ein gangbarer Weg, zumindest, wenn die Ein- und Ausgabewerte den Wertebereich des Datentyps nicht sprengen.

        Tschö, Auge

        --
        Ein echtes Alchimistenlabor musste voll mit Glasgefäßen sein, die so aussahen, als wären sie beim öffentlichen Schluckaufwettbewerb der Glasbläsergilde entstanden.
        Hohle Köpfe von Terry Pratchett
        1. Tach!

          Das wird auch in anderen Kontexten empfohlen. Mir war so, das hier mal in Bezug auf Geldbeträge in MySQL gelesen zu haben.

          Dafür gibt es den Datentyp DECIMAL, der keine binärsystembedingten Eigenheiten aufweist.

          Das Problem stellt sich mit Integer-Zahlen nicht, also ja, das ist ein gangbarer Weg, zumindest, wenn die Ein- und Ausgabewerte den Wertebereich des Datentyps nicht sprengen.

          PHP kennt aber keinen vergleichbaren Typ. Integer hat den Nachteil, dass man sich auf eine feste Nachkommastellenanzahl festlegen muss. Es gibt aber auch die Extensions BC Math und GMP, die mit genaueren Zahlen umgehen können.

          dedlfix.

      2. @@Henry

        Hallo Gunnar,

        Dann vermute ich mal, es ist sinnvoller lange Operationen besser als Ganzwert abzuarbeiten und erst am Ende wieder in einen gebrochenen Wert ändern?

        Meist ist es sinnvoll, mit „genauen“ Werten zu rechnen (was auch heißt, durch die Beschränktheit der Genauigkeit von Zahlen im Computer geringe Abweichungen inkaufzunehmen) und den Wert erst bei der Ausgabe wie gewünscht zu formatieren. In PHP wie du schon sagtest mit round($total, 2); in JavaScript wäre’s total.toFixed(2).

        Bei Geldbeträgen – wenn man tatsächlich jedes Zwischenergebnis auf ganze Cent runden will – kann es auch sinnvoll sein, mit Integerarithmeitik in Cent zu rechnen und erst bei der Ausgabe in Euro (Dollar, …) umzurechnen.

        LLAP 🖖

        --
        „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
        „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

        —Marc-Uwe Kling
        1. Hallo Gunnar,

          Bei Geldbeträgen – wenn man tatsächlich jedes Zwischenergebnis auf ganze Cent runden will – kann es auch sinnvoll sein, mit Integerarithmeitik in Cent zu rechnen und erst bei der Ausgabe in Euro (Dollar, …) umzurechnen.

          Ich hatte da eigentlich einen anderen Ansatz im Kopf. Nicht jedes Zwischenergebnis runden, sondern die Dezimalwerte als String behandeln, das Trennzeichen entfernen und den Wert dann als Integer zu deklarieren. Also nicht 123,45*100 oder ceil oder so sondern (INT)12345

          Gruss
          Henry

          --
          Meine Meinung zu DSGVO & Co:
          „Principiis obsta. Sero medicina parata, cum mala per longas convaluere moras.“
        2. Hallo,

          Bei Geldbeträgen – wenn man tatsächlich jedes Zwischenergebnis auf ganze Cent runden will – kann es auch sinnvoll sein, mit Integerarithmeitik in Cent zu rechnen und erst bei der Ausgabe in Euro (Dollar, …) umzurechnen.

          Ich glaube sogar, es wird in Hundertstel-Cent gerechnet, wenn z.B. mit Zinsen und Zinseszins hantiert werden muss.

          Gruß
          Kalk

          1. @@Tabellenkalk

            Bei Geldbeträgen – wenn man tatsächlich jedes Zwischenergebnis auf ganze Cent runden will – kann es auch sinnvoll sein, mit Integerarithmeitik in Cent zu rechnen und erst bei der Ausgabe in Euro (Dollar, …) umzurechnen.

            Ich glaube sogar, es wird in Hundertstel-Cent gerechnet, wenn z.B. mit Zinsen und Zinseszins hantiert werden muss.

            Bei der Umsatzsteuer und Netto/Brutto wird mit ganzen Cents gerechnet. ☞ Runden mit PHP

            Durch den neuen Markdown-Parser ist die Tabellendarstellung des Postings fehlerhaft. Könnte das ein Admin bitte in Ordnung bringen? @Matthias Apsel

            LLAP 🖖

            --
            „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
            „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

            —Marc-Uwe Kling
            1. Hallo Gunnar,

              es ist in der Finanzmathematik eigentlich üblich, Geldberechnungen mit 4 Nachkommastellen durchzuführen (für Euro-Werte). Mehr ist nicht nötig. Rechnet man mit Cent, nimmt man 2 Nachkommastellen. Genauer zu rechnen verbietet einem aber auch keiner, soweit ich weiß.

              Mit Cents und ohne Nachkommastellen zu rechnen KANN funktionieren, setzt aber voraus, dass man genau auf die Reihenfolge der Operationen achtet. Divisionen, die Nachkommastellen erzeugen können, dürfen dann erst am Ende stattfinden. Mit der Folge, dass man ggf. ziemlich hohe Zwischenwerte erhält, die den Integer-Zahlenraum sprengen.

              Es ist also durchaus ok, in PHP mit floats zu rechnen. Speichern oder ausgeben tut man sie dann in EUR auf 2 Nachkommastellen gerundet.

              Ich habe gerade eine Weile gegoogelt, ob es bspw. BAFIN-Vorschriften für die Finanzdienstleister gibt, wie sie mit Geld zu rechnen haben. Gefunden habe ich nichts. Ich arbeite zwar bei einem BAFIN-überwachten Unternehmen, aber nicht in einem entsprechenden Bereich. Ich weiß nur, dass wir vor 20 Jahren, bei der Umstellung von DM auf EUR, sehr genaue Vorgaben hatten, wie Berechnungen auszuführen waren und wann zu runden war. Da mussten 4 Nachkommastellen für Zwischenergebnisse verwendet werden.

              Eine Kettenrechnung, wie Henry sie ausführt, sollte nach jeder Iteration auf 4 Nachkommastellen gerundet werden. Das verhindert zwar den prinzipiellen Float-Fehler nicht, sorgt aber dafür, dass man nicht durch Fehlerfortpflanzung ein Hunderstelcent verschlampt.

              Rolf

              --
              sumpsi - posui - clusi
              1. Hallo

                ich habe heute den Abgabenbescheid von der Gemeinde bekommen.

                Kosten für die Gewässerunterhaltung:
                Versiegelte Fläche: 0,02260 €/qm
                übrige Fläche: 0,00019 €/qm.

                Gruß
                Jürgen

                1. Hallo JürgenB,

                  ja, okay, bei so kleinen Werten scheint eine weitere Stelle sinnvoll, um genügend signifikante Stellen zu behalten.

                  Rolf

                  --
                  sumpsi - posui - clusi
      3. Hallo,

        FAQ: Wieso habe ich beim Rechnen mit Dezimalzahlen Rechenfehler?

        Sehr informativ, danke.

        wird immer wieder gern empfohlen. ;-)

        Also "Nicht exakt darstellbare Zahlen im Binärsystem". Das bedeutet dann wohl, in der Schleife ist der wahre (im System unsichtbare) Wert im Hintergrund beim Breakpoint ein anderer, als bei einer gleichen (im sichtbaren Bereich) Einzelrechnung.

        Nein. Es bedeutet vielmehr, dass Fließkommazahlen intern immer um mindestens ein Bit genauer gespeichert als sie tatsächlich angezeigt werden. So werden Zahlen zur Darstellung also immer gerundet (und sei es auf 12 Nachkommastellen oder so).
        Bei mehreren Additionen in Folge summiert sich aber auch der Fehler auf (Abweichung von gespeichertem zu gerundeten Anzeigewert), und nach ein paar aufeinanderfolgenden Schritten wird er so groß, dass die Rundung ihn nicht mehr ausbügelt.

        Wenn beim Gartenbau mal ein Pflasterstein ein paar Millimeter zu klein ist, macht das noch nicht viel; wenn du aber fünf Pflastersteine aneinanderlegst, die alle einen Hauch zu klein sind, passt es irgendwann mit dem Anschluss nicht mehr.

        Dann vermute ich mal, es ist sinnvoller lange Operationen besser als Ganzwert abzuarbeiten und erst am Ende wieder in einen gebrochenen Wert ändern?

        Ja, das ist eine oft empfohlene Methode und funktioniert gut, wenn du die Wertebereiche vorher überblicken kannst.

        Schönes Wochenende,
         Martin

        --
        Ach, macht ihr da Ohm doch Watt ihr Volt.
        1. Hallo Der,

          Hallo,

          FAQ: Wieso habe ich beim Rechnen mit Dezimalzahlen Rechenfehler?

          Sehr informativ, danke.

          wird immer wieder gern empfohlen. ;-)

          Also "Nicht exakt darstellbare Zahlen im Binärsystem". Das bedeutet dann wohl, in der Schleife ist der wahre (im System unsichtbare) Wert im Hintergrund beim Breakpoint ein anderer, als bei einer gleichen (im sichtbaren Bereich) Einzelrechnung.

          Nein. Es bedeutet vielmehr, dass Fließkommazahlen intern immer um mindestens ein Bit genauer gespeichert als sie tatsächlich angezeigt werden. So werden Zahlen zur Darstellung also immer gerundet (und sei es auf 12 Nachkommastellen oder so).

          Ich vermute mal du meinst das anders, klingt aber so als wenn der interne Wert genauer wäre als der exakt angegebene Wert, zb. 3,4 wird zu 3,39999999… symbolisch gesehen. Das ist für mich dann nicht genauer gespeichert.

          Gruss
          Henry

          --
          Meine Meinung zu DSGVO & Co:
          „Principiis obsta. Sero medicina parata, cum mala per longas convaluere moras.“
          1. Hallo,

            Ich vermute mal du meinst das anders, klingt aber so als wenn der interne Wert genauer wäre als der exakt angegebene Wert, zb. 3,4 wird zu 3,39999999… symbolisch gesehen. Das ist für mich dann nicht genauer gespeichert.

            Du musst bedenken, dass du mit einem anderen Zahlensystem arbeitest als der Rechner. Der speichert nämlich gerne mal im Binärsystem und da ist die scheinbar glatte 3,4 vielleicht total krumm und das für dich scheinbar schräge 3,399999 viel genauer…

            Gruß
            Kalk

          2. @@Henry

            Hallo Der,

            Der ist alt. (Der Witz, nicht der Der. 😆)

            Ich vermute mal du meinst das anders, klingt aber so als wenn der interne Wert genauer wäre als der exakt angegebene Wert, zb. 3,4 wird zu 3,39999999… symbolisch gesehen. Das ist für mich dann nicht genauer gespeichert.

            Für den einen[1] ist es genauer, für den anderen[2] der vielleicht längste Dezimalbruch der Welt.

            LLAP 🖖

            --
            „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
            „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

            —Marc-Uwe Kling

            1. für den Computer, der im Binärsystem rechnet ↩︎

            2. für dich, der du im Dezimalsystem rechnest ↩︎

            1. @@Gunnar Bittersmann

              Trennung: Binärs-ystem

              Go home, automatische Silbentrennung, you’re drunk. (Safari, iOS)

              LLAP 🖖

              --
              „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
              „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

              —Marc-Uwe Kling
              1. Hallo,

                Trennung: Binärs-ystem

                Go home, automatische Silbentrennung, you’re drunk. (Safari, iOS)

                auch Menschen sind da manchmal phantasievoll. Neulich gesehen: Sam-stag. Und das von jemandem, der immer perfekt sein will. :-P
                Die Faustregel "Trenne nie st" galt noch nie für zusammengesetzte Wörter, bei denen s-t die Klebestelle ist.

                Berüchtigt für Silbentrennung per Zufall (da, wo halt zufällig gerade die Zeile zu Ende ist), sind Zeitungsverlage. Die Stuttgarter Zeitung ist ein solcher Vertreter.

                Ciao,
                 Martin

                --
                Ach, macht ihr da Ohm doch Watt ihr Volt.
                1. @@Der Martin

                  Die Faustregel "Trenne nie st" galt noch nie für zusammengesetzte Wörter, bei denen s-t die Klebestelle ist.

                  Früher™, als man noch zwischen st und ſt zu unterscheiden wusste.

                  Da galt: „Trenne nie ſt“ (auch nicht im Sperrsatz), aber „trenne st“.

                  Wach-ſtube vs. Wachs-tube.

                  LLAP 🖖

                  --
                  „Man kann sich halt nicht sicher sein“, sagt der Mann auf der Straße, „dass in einer Gruppe Flüchtlinge nicht auch Arschlöcher sind.“
                  „Stimmt wohl“, sagt das Känguru, „aber immerhin kann man sich sicher sein, dass in einer Gruppe Rassisten nur Arschlöcher sind.“

                  —Marc-Uwe Kling