axel: Fließkommafehler

Guten Morgen geschätzte Leser!

Javascript macht ja bekanntlich Fließkommafehler (0.011*100=1.0999999999999998). (Das warum ist mir eigentlich egal, obwohl ich nicht verstehe, daß das nötig ist - mein uraltes Turbo-Pascal konnte das besser.)
Die häufig angebotene Lösung heißt runden. Da ich aber den Benutzern auch mehrere Nachkommastellen anbieten will, kann ich also erst nach der (z.B.) 9ten Stelle runden (Math.round(X*1e9)/1e9). Nun kommt mein Problem: Da der Benutzer auch größere Zahlen (Größenordnung "nur" 1e7) eingeben wird, führt das dazu, daß durch 1e7*1e9 die Zahlengenauigkeit am Ende ist und mir der Fließkommafehler erhalten bleibt (Beispiel: Math.round(0.011*100*1e7*1e9)/1e9=10999999.999999998).
Noch zum Verständnis: Es geht um die Umrechung physikalischer Größen in verschiedene Einheiten. D.h., der Benutzer gibt Werte ein, das Javascript soll umrechnen. Ich gebe also nur feste Umrechnungsfaktoren vor und habe auf die Auswahl der Zahlen somit keinen Einfluß.
Es würde mich sehr freuen, wenn jemand einen Vorschlag für mich hat, wie ich auf korrekte Werte komme.
Eine schöne Woche wünscht Euch allen
axel

  1. Hallo axel,

    Ich habe gerade mal etwas rumprobiert, aber bei allen Versuchen auf mathematischer Ebene (nachkommastellen abschneiden, gesondert bearbeiten etc.) bin ich gescheitert (über die selben Rundungsfehler). Also bliebe noch die Zahl in einen String umzuwandlen, ihn auseinander zunehmen, auf Nullen zu prüfen und entsprechend zu behandeln (ohne Kommastellen) und dann wieder in eine Zahl zu überführen. Das ist aber ein irrer Aufwand.
    Deshalb würde ich sagen, wenn du "blos" Umrechnungen physikalischer Größen anbieten willst, sollte das ganze auch noch recht einfach als Java-Applet umsetzbar sein. Ist zwar proprietär, sieht nicht so hübsch aus.... aber es geht wenigstens.

    Vielleicht hilft dir auch ActionScript aus Flash weiter, aber da ich das gerade nicht installiert haben kann ich dir nichts genaues sagen. Es könnte sein, dass ActionScript auf der JavaScript-Engine des Browsers aufsetzt und dann sind wir wo wir schon mal waren.

    Bye Ed X

  2. Hallo Axel

    Noch zum Verständnis: Es geht um die Umrechung physikalischer Größen in verschiedene Einheiten. D.h., der Benutzer gibt Werte ein, das Javascript soll umrechnen. Ich gebe also nur feste Umrechnungsfaktoren vor und habe auf die Auswahl der Zahlen somit keinen Einfluß.

    Ich hoffe, dieser Link hilft dir weiter:

    http://pc-anfaenger.de/script/jsrund1.htm

    Gruß

    Antje

    1. Hallo Antje,

      vielen Dank für Deine Mühe, aber Dein Script bietet ja "nur" ein "komfortables" Runden an und beschäftigt sich nicht mit dem angesprochenen Fließkommafehler. Ruf doch mal so
      runden(0.011*100*1e7,-9)
      Dein Script auf und Du wirst sehen, daß es den gleichen Fehler (wie in meinem ersten posting beschrieben) erzeugt.
      Noch eine Frage an Dich am Rande: Warum tauschst Du ein Komma gegen einen Punkt nicht so aus:
      zahl=zahl.replace(",",".");

      viele Grüße
      axel

      1. Hallo Axel

        Noch eine Frage an Dich am Rande: Warum tauschst Du ein Komma gegen einen Punkt nicht so aus:
        zahl=zahl.replace(",",".");

        Weil es dann nur in den Browsern ab Version 4 läuft. So läuft es auch in alten Browsern.

        Gruß

        Antje

  3. Good afternoon geschätzter axel,

    Javascript macht ja bekanntlich Fließkommafehler (0.011*100=1.0999999999999998). (Das warum ist mir eigentlich egal,

    Sollte es aber nicht, denn es gibt offensichtlich eine Lösung, und die liegt im binären Zahlensystem.
    Den Lösungsansatz findest Du hier:
    http://www.rabich.de/javascript_goodies/zahlenspiele.htm#Fehlerkorrektur

    HTH,

    Bye Ed X

    1. Guten Morgen Ed X!

      Zuvor vielen Dank für Deine Hilfe.
      Nun zum Inhalt.

      Javascript macht ja bekanntlich Fließkommafehler (0.011*100=1.0999999999999998). (Das warum ist mir eigentlich egal,

      Sollte es aber nicht, denn es gibt offensichtlich eine Lösung, und die liegt im binären Zahlensystem.
      Den Lösungsansatz findest Du hier:
      http://www.rabich.de/javascript_goodies/zahlenspiele.htm#Fehlerkorrektur

      Auch hier dient das binäre Zahlensystem nur als Erklärung, warum das passiert. Die Lösung, die dort "Korrektur" genannt wird, basiert aber leider auch nur auf "modifiziertem" Runden (statt runden, Zahl um 0.1 erhöht und Nachkommastellen abgeschnitten) in der Form wie ich es in meinem ersten posting beschrieben habe...

      Alles in allem scheint es keine (für mich) befriedigenden Ergebnisse zum Thema Zahlen in Javascript zu geben. Ich stelle mir nur den Fall von etwas aufwendigeren Berechnungen vor, wo sich solche Fließkommafehler ja durchaus "hochschaukeln" können oder wo ergebnisabhängig verzweigt wird (if x<=1.1  s.o.) und das dann falsch! Man kann ja auch nicht nach jedem Rechenschritt runden, da man sich dann entweder in den Nachkommastellen oder in der Zahlengröße sehr stark einschränken muß.

      Wieso muß ich eigentlich immer wieder lesen (nicht nur hier im Forum), daß Javascript da gar keinen Fehler macht, sondern daß das am binären Zahlensystem liegt (und das so seien muß bzw. alles richtig ist)? Mein bereits erwähnter uralter (und ehemals heiß geliebter) Turbo-Pascal-Compiler ist doch wohl um das binäre Zahlensystem letztendlich auch nicht herumgekommen (oder?). Trotzdem konnte man damit vernünfig rechnen.

      Vielleich komme ich auf Deinen ersten Vorschlag zurück, Ed X, und werde mich mal mit Java beschäftigen, obwohl ich das zum einen unbefriedigend finde und mir zum anderen nicht sicher bin, ob das Ergebnis bessr ist (siehe http://www.teamone.de/selfhtml/sfarchiv/2000_3/t17812.htm).

      frohes Schaffen wünscht (trotz allem)
      axel

      1. Hallo axel!

        Auch hier dient das binäre Zahlensystem nur als Erklärung, warum das passiert. Die Lösung, die dort "Korrektur" genannt wird, basiert aber leider auch nur auf "modifiziertem" Runden (statt runden, Zahl um 0.1 erhöht und Nachkommastellen abgeschnitten) in der Form wie ich es in meinem ersten posting beschrieben habe...

        Wenn du nicht um 0,1 erhöhst sondern die Zahl mit 10^(Zahl der Nachkommastellen +1) malnimmst, dann 5 addierst, dann die letze Stelle per Stringoperation abschneidest und dann per Stringoperationen das Dezimalkomma an die richtige Stelle einfügst, dann rundest du richtig. (Und im Gegensatz zu den round(..)/100 Lösungen auch ohne das der Fehler bei ungünstigen Zahlen wieder reinkommt.) [2]
        Bei Zahlen in Exponentialdarstellung wirds aufwändig.

        Alles in allem scheint es keine (für mich) befriedigenden Ergebnisse zum Thema Zahlen in Javascript zu geben. Ich stelle mir nur den Fall von etwas aufwendigeren Berechnungen vor, wo sich solche Fließkommafehler ja durchaus "hochschaukeln" können oder wo ergebnisabhängig verzweigt wird (if x<=1.1  s.o.) und das dann falsch! Man kann ja auch nicht nach jedem Rechenschritt runden, da man sich dann entweder in den Nachkommastellen oder in der Zahlengröße sehr stark einschränken muß.

        Das ist kein Javascript-Problem. Um das zu untermauern müsste ich dir jetzt aber doch erklären wie das mit der Zahlenrepresäntation im Rechner so ist.

        Ein Minibeispiel kann ich mir aber nicht verkneifen:
        Rechne mal ((1E10 + 1E-10)-1E10)*1E10) mit einem System deiner Wahl aus. Es wird Null rauskommen und nicht Eins.
        Bei aufwändigeren Berechnungen mit begrenzter Stellenzahl[1] kommt man um eine Fehleranaylyse nicht drumrum.

        Wieso muß ich eigentlich immer wieder lesen (nicht nur hier im Forum), daß Javascript da gar keinen Fehler macht,

        Die Aussage lautet: es ist kein JavaScript-Rechen-Fehler, denn dannach wird i.a gefragt.
        Natürlich ist die ungerundetet Ausgabe (und das Fehlen formatierender Ausgabefunktionen) ein schwerwiegender Entwurfsfehler von Javascript.

        .... Turbo-Pascal-Compiler ist doch wohl um das binäre Zahlensystem letztendlich auch nicht herumgekommen (oder?). Trotzdem konnte man damit vernünfig rechnen.

        Binär ja, Vernünftig ja, auf jeden Fall richtig:nein.

        Die Turbo-Pascal Programmierer hatten nur mehr Durchblick was Anwendung ihrer Ausgaberoutine für praktische Aufgaben angeht. Die rundet nämlich auf soviele Stellen, wie meistens noch sinnvoll sind.

        Vielleich komme ich auf Deinen ersten Vorschlag zurück, Ed X, und werde mich mal mit Java beschäftigen, obwohl ich das zum einen unbefriedigend finde und mir zum anderen nicht sicher bin, ob das Ergebnis bessr ist (siehe http://www.teamone.de/selfhtml/sfarchiv/2000_3/t17812.htm).

        Keine Programmiersprache [1] wird da grundsätzlich besser sein - es gibt nur welche, die Funktionen zur Ausgabeformatierung besitzen (ähm...eigentlich ist Javasript die einzige (höhere) die keine hat).

        Gruss,
         Carsten

        [1] beim PC werden die Berechnungen typischerweise von der CPU selbst gemacht und die verarbeitet 80 bit Mantisse, egal von welchem Programm sie benutzt wird.

        [2] Wichtig ist niemals durch 10 zu teilen, da 0.1 ein unendlicher Binärbruch ist, der weitere Rechenfehler einführt.