Andreas Lindig: Rechenfehler in JavaScript

Hallo Forum,

ích bekomme in JavaScript folgenden Rechenfehler:
2937.7 - 326.3 = 2611.3999999999996
richtig wäre     2611.4

Nun könnte man sagen: "mein jott, watt is der Kerl aber auch empfindlich..." Das Problem ist nur, daß ich in einer Schleife jeweils den gleichen Betrag vom Ergebnis wieder abziehe und nach soundsovielen Schritten _genau_ auf einer vorbestimmten Zahl rauskommen muß, sonst fehlt ein Schleifendurchgang. Ich habe jetzt die Abbruchbedingung dahingehend geändert, daß der Endwert auch noch um 0.1 unterschritten werden kann und es Funktioniert - bei bisherigen Tests. Aber ich weiß nicht, was da in anderen Konstellationen noch für Abweichungen entstehen; ich finde diese Lösung ein wenig dirty. Kann ich JS nicht anweisen so simple Rechnungen bitteschön genau auszuführen?

Gruß, Andreas

--
SELFFORUM - hier werden Sie geholfen,
auch in Fragen zu richtiges Deutsch
  1. ích bekomme in JavaScript folgenden Rechenfehler:
    2937.7 - 326.3 = 2611.3999999999996
    richtig wäre     2611.4

    Auch hier <seufz>

    Du kannst mit Binären Zahlen nie genau Fließkommaberechnungen machen.

    http://www3.futureware.at/artikel/zahlen.htm

    Struppi.

    1. 你好 Struppi,

      Du kannst mit Binären Zahlen nie genau Fließkommaberechnungen machen.

      Naja, das stimmt so ja nicht. Binaer-Zahlen schieben nur die Problem-Zahlen
      auf andere Stellen; dafuer ist dann das, was in dezimal problematisch
      waere, in binaer uU recht einfach.

      再见,
      克里斯蒂安

      --
      Microsoft: Where do you want to go today?
      Linux: Where do you want to go tomorrow?
      FreeBSD: Are you guys coming, or what?
      1. Du kannst mit Binären Zahlen nie genau Fließkommaberechnungen machen.

        Naja, das stimmt so ja nicht. Binaer-Zahlen schieben nur die Problem-Zahlen
        auf andere Stellen; dafuer ist dann das, was in dezimal problematisch
        waere, in binaer uU recht einfach.

        so verstehe ich das jetzt auch, also Problemzahlen bei diesen Berechnungen sind in Binärschreibweise Endlosbrüche oder so was ja?

        @Struppi: danke für den Link. Da wird von "E-Bereich" gesprochen, nur wie finde ich denn den relevanten Bereich? Ich weiß doch vorher gar nicht, zu wieviel sich die Fehler in der Schleife addiert haben.

        Gruß, Andreas

        --
        SELFFORUM - hier werden Sie geholfen,
        auch in Fragen zu richtiges Deutsch
        1. 你好 Andreas,

          so verstehe ich das jetzt auch, also Problemzahlen bei diesen
          Berechnungen sind in Binärschreibweise Endlosbrüche oder so was ja?

          Jain, sie koennen auch periodisch sein. Bestes Beispiel: rechne mal
          0,1 dezimal um nach binaer :)

          再见,
          克里斯蒂安

          --
          1 + 1 = 3 für gosse Werte von 1.
          1. so verstehe ich das jetzt auch, also Problemzahlen bei diesen
            Berechnungen sind in Binärschreibweise Endlosbrüche oder so was ja?

            Jain, sie koennen auch periodisch sein.

            hat für mich dazugezählt :-) mein mathematisches Differenzierungsvermögen sollte doch hier bekannt sein ;-)

            Gruß, Andreas

            --
            SELFFORUM - hier werden Sie geholfen,
            auch in Fragen zu richtiges Deutsch
  2. Hallo Andreas Lindig,

    ích bekomme in JavaScript folgenden Rechenfehler:
    2937.7 - 326.3 = 2611.3999999999996
    richtig wäre     2611.4

    ich glaube, da erwartest Du etwas zu viel. Die Abweichung befindet sich in der 17. Stelle. Das ist besser als "double precision". "Normale" Rechner mit "normalen" Programmiersprachen können nicht mehr. Runde doch einfach mit z.B. toFixed oder mit mal 10^n, Math.round, durch 10^n.

    Gruß, Jürgen

  3. Hi,

    Ich habe jetzt die Abbruchbedingung dahingehend geändert, daß der Endwert auch noch um 0.1 unterschritten werden kann und es Funktioniert - bei bisherigen Tests. Aber ich weiß nicht, was da in anderen Konstellationen noch für Abweichungen entstehen;

    Runde doch einfach ein wenig?!

    Gruß, Cybaer

    --
    Hinweis an Fragesteller: Fremde haben ihre Freizeit geopfert, um Dir zu helfen. Helfe Du auch im Archiv Suchenden: Beende deinen Thread mit einem "Hat geholfen" oder "Hat nicht geholfen"!
  4. zu den Rundungsvorschlägen:

    Ich muß eine Strecke - z.B. zwischen 127 und 16384 - in eine bestimmte Anzahl gleichmäßige Abschnitte teilen, z.B. in 17 Stück. Dazu berechne ich die Länge des Abschnitts (16384-127)/(17-1) und in der Schleife gehe ich immer in dieser Schrittweite voran. Wenn ich jedes Zwischenergebnis runden würde, käme ich ja ganz woanders am Ende raus, also runde ich absichtlich nicht. Ich könnte nur runden, wenn ich wüßte, an welcher Stelle die Abweichung auftritt. Im Ausgangsbeispiel 2611.3999999999996 ^= 2611.4 wüße ich: erste Nachkommastelle, aber die Abweichung kann ja immer woanders sein.

    Mein Programm wird jetzt mit meiner Pi-mal-Daumen-Toleranz-Zugabe wohl funktionieren, aber interessant ist das Problem ja trotzdem mal ;-)

    Gruß, Andreas

    --
    SELFFORUM - hier werden Sie geholfen,
    auch in Fragen zu richtiges Deutsch
    1. Hallo Andreas Lindig,

      bei wiederholten Additionen wirst Du immer Probleme mit der Ungenauigkeit haben, da sich die Fehler ja addieren. Evtl. kannst Du das Problem umgehen, wenn Du multiplizierst. Also statt

        
      wert = startwert;  
      for(i=0;i<ende;i++) {  
       ...  
       wert = wert + increment;  
      }  
      
      

      besser

        
      for(i=0;i<ende;i++) {  
       wert = startwert + i*increment;  
       ...  
      }  
      
      

      Gruß, Jürgen

      1. 你好 JürgenB,

        besser

        for(i=0;i<ende;i++) {
        wert = startwert + i*increment;
        ...
        }

          
        Eh, das ist aber doch dasselbe wie `wert = startwert + ende * increment`{:.language-javascript} -- wozu dann ueberhaupt noch die Schleife?  
          
        再见,  
         克里斯蒂安  
        
        -- 
        Ich bewundere wirklich den Sinn der Bienen für kollektive Verantwortung. Obwohl sich einzelne Bienen hin und wieder bekämpfen, herrscht zwischen Ihnen grundsätzlich ein starkes Gefühl für Eintracht und Zusammenarbeit. Wir Menschen gelten als sehr viel weiter entwickelt, doch mitunter rangieren wir sogar hinter kleinen Insekten.  
        
        
        1. Eh, das ist aber doch dasselbe wie wert = startwert + ende * increment -- wozu dann ueberhaupt noch die Schleife?

          weil ich alle Zwischenergebnisse brauche. Ich will die Punkte wissen, wo ich bei gleichmäßiger Teilung der Strecke sozusagen die Pfähle einschlagen muß.

          Gruß, Andreas

          --
          SELFFORUM - hier werden Sie geholfen,
          auch in Fragen zu richtiges Deutsch
          1. Hallo,

            weil ich alle Zwischenergebnisse brauche. Ich will die Punkte wissen, wo ich bei gleichmäßiger Teilung der Strecke sozusagen die Pfähle einschlagen muß.

            Das geht nur in begrenzter Genauigkeit. Die Additionsungenauigkeit bekommst Du aber weg, indem Du die Positionen der Pfähle nach der Berechnung so genau, wie erforderlich, rundest.
            Beispiel:

            var start = 127;
            var ende = 16384;
            var teile = 10
            var schrittw = (ende-start)/teile;
            document.writeln("Strecke = " + (ende-start) + "<br>");
            document.writeln("Schrittweite = " + schrittw + "<br>");
            var strecke = 0;
            for (i=0; i<teile; i++) {
              strecke = Math.round((strecke + schrittw)*100)/100;
              document.writeln("Nach Teil " + (i+1) + " ist Strecke = " + strecke + "<br>");
            }

            Ohne Rundung käme heraus:
            Strecke = 16257
            Schrittweite = 1625.7
            Nach Teil 1 ist Strecke = 1625.7
            Nach Teil 2 ist Strecke = 3251.4
            Nach Teil 3 ist Strecke = 4877.1
            Nach Teil 4 ist Strecke = 6502.8
            Nach Teil 5 ist Strecke = 8128.5
            Nach Teil 6 ist Strecke = 9754.2
            Nach Teil 7 ist Strecke = 11379.900000000001
            Nach Teil 8 ist Strecke = 13005.600000000002
            Nach Teil 9 ist Strecke = 14631.300000000003
            Nach Teil 10 ist Strecke = 16257.000000000003

            Aber 16257 _ist_ nunmal _dezimal_ in 10 gleiche Teile teilbar. Die gerundete Variante kann das auch.

            Willst Du aber bspw. nur 7 Teile, dann kommt es halt dauf an, mit welcher Abweichung Du leben kannst. Beispielsweise wäre die, mit Rundung auf 4 Nachkommastellen (Math.round((strecke + schrittw)*10000)/10000;):
            Strecke = 16257
            Schrittweite = 2322.4285714285715
            Nach Teil 1 ist Strecke = 2322.4286
            Nach Teil 2 ist Strecke = 4644.8572
            Nach Teil 3 ist Strecke = 6967.2858
            Nach Teil 4 ist Strecke = 9289.7144
            Nach Teil 5 ist Strecke = 11612.143
            Nach Teil 6 ist Strecke = 13934.5716
            Nach Teil 7 ist Strecke = 16257.0002

            Denn 16257 ist nunmal auch dezimal nicht endlich in 7 Teile teilbar.
                 ______
            2322,428571

            viele Grüße

            Axel

        2. Hallo Christian Kruse,

          Eh, das ist aber doch dasselbe wie wert = startwert + ende * increment -- wozu dann ueberhaupt noch die Schleife?

          stimmt, aber nur wenn die Zwischenwerte nicht benötigt werden. Daher die "..." in der Schleife.

          Gruß, Jürgen