Man muss sich nur entscheiden, wie viele Nachkommastellen man tatsächlich haben möchte - man kann nicht alles haben und auch noch essen :-)
Numerische Fehler häufen sich mit jeder weiteren Operation, und wenn man sie nicht frühzeitig abstellt, werden sie immer größer. Numerische Bibliotheken, die Ergebnisse präsentieren, die sauber aussehen, schneiden einfach die letzten 2 Ziffern bei jedem Schritt ab, numerische Koprozessoren haben aus demselben Grund eine "normale" und eine "volle" Länge. Cuf-offs sind billig für einen Prozessor, aber sehr teuer für Sie in einem Skript (Multiplizieren und Dividieren und die Verwendung von pov(...)). Eine gute Mathe-Lib würde floor(x,n) zur Verfügung stellen, um den Cut-Off für Sie zu erledigen.
Sie sollten also zumindest eine globale Variable/Konstante mit pov(10,n) erstellen - was bedeutet, dass Sie sich für die benötigte Genauigkeit entschieden haben :-) Dann mach das:
Math.floor(x*PREC_LIM)/PREC_LIM // floor - you are cutting off, not rounding
Sie könnten auch weiter rechnen und erst am Ende abschneiden - vorausgesetzt, dass Sie die Ergebnisse nur anzeigen und nicht mit Wenns arbeiten. Wenn Sie das tun können, dann könnte .toFixed(...) effizienter sein.
Wenn Sie if-s/Vergleiche durchführen und nicht abschneiden wollen, benötigen Sie außerdem eine kleine Konstante, die in der Regel eps heißt und eine Dezimalstelle höher ist als der maximale erwartete Fehler. Nehmen wir an, die letzten beiden Dezimalstellen sind Ihre Abgrenzung - dann hat Ihr eps eine 1 an der drittletzten Stelle (drittniedrigstwertigste Stelle) und Sie können damit vergleichen, ob das Ergebnis im eps-Bereich des erwarteten Fehlers liegt (0,02 -eps < 0,1*0,2 < 0,02 +eps).
157 Stimmen
Eigentlich liegt der Fehler daran, dass es keine Möglichkeit gibt, die
0.1
in eine endliche binäre Gleitkommazahl.19 Stimmen
Die meisten Brüche lassen sich nicht mit exakter Genauigkeit in eine Dezimalzahl umwandeln. Eine gute Erklärung finden Sie hier: docs.python.org/release/2.5.1/tut/node16.html
8 Stimmen
Mögliche Duplikate von Ist die Mathematik von JavaScript kaputt?
4 Stimmen
@AaronDigulla:
(new Number(0.1)).valueOf()
es0.1
.65 Stimmen
@SalmanA: Dass Ihre JavaScript-Laufzeitumgebung dieses Problem vor Ihnen verbirgt, bedeutet nicht, dass ich falsch liege.
12 Stimmen
Ich stimme Aaron nicht zu, es gibt Möglichkeiten, 0,1 perfekt und vollständig binär zu codieren. Aber IEEE 754 definiert dies nicht unbedingt. Stellen Sie sich eine Darstellung vor, bei der Sie einerseits den ganzzahligen Teil binär kodieren, andererseits den dezimalen Teil, bis zu n Dezimalstellen, ebenfalls binär, wie eine normale ganze Zahl > 0, und schließlich die Position des Dezimalpunkts. Nun, Sie würden 0,1 perfekt darstellen, ohne Fehler. Btw, da JS intern eine endliche Anzahl von Dezimalstellen verwendet, könnten die Entwickler genauso gut den Mut haben, diesen Fehler bei den letzten Dezimalstellen zu vermeiden.
1 Stimmen
@epascarello In dieser Frage geht es darum, warum das passiert, in dieser Frage darum, wie man es beheben kann. Die Antworten sind unterschiedlich, also sind auch die Fragen unterschiedlich.
1 Stimmen
@AaronDigulla warum JS tut dies und C# nicht? Ich habe bemerkt, dass JS dies auch bei der Summe macht, was keinen Sinn ergibt. Warum kann nicht addieren 1.12345678 + 1.12345678 richtig. Keine Multiplikation, keine Division, kein Überlauf
1 Stimmen
Ich habe zwei Gleichungen/Formeln für die Berechnung des umgekehrten Prozentsatzes geschrieben, die Sie hier finden können: stackoverflow.com/a/54125117/850840 und hier stackoverflow.com/a/54125466/850840
2 Stimmen
@PawelCioch Haben Sie mit genau denselben Zahlen getestet? Hast du das binäre Muster zum Initialisieren der Variablen verwendet (sonst bekommst du Rundungsfehler vom Float->String-Konverter)? Die meisten Sprachen verwenden die CPU für Fließkomma-Mathematik (also verhalten sie sich gleich), nur der Code zum Parsen und Formatieren der Zahlen ist anders.
1 Stimmen
So lustig und noch seltsamer mit 0.1 + 0.2 _
2 Stimmen
Binäre Brüche können nur 1/2, 1/4, 1/8, 1/16, 1/32... richtig verarbeiten. Und weil 0,3 und 0,2 keine Brüche sind, die mit den obigen Brüchen gebildet werden können, gibt es dieses "seltsame" Verhalten. Dies hier hat mir sehr geholfen: youtube.com/watch?v=PZRI1IfStY0
2 Stimmen
@FabienHaddadi (ich kommentiere das hauptsächlich, um mein Verständnis zu festigen) Ich denke, es ist eine Frage der Definition. Für Sie bedeutet "eine Zahl binär kodieren" "eine Möglichkeit zu haben, diese Zahl mit 0 und 1 darzustellen". Für Aaron bedeutet es, "sie als endliche (pseudo-)geometrische Summe mit 2 als gemeinsamem Verhältnis und Gewichten von 0 oder 1 zu schreiben".
2 Stimmen
@user56202: Ja, es muss eine Frage der Definitionen sein. Ich habe das Binärsystem auf einem alten wissenschaftlichen Taschenrechner HP48 gelernt. Früher wurde eine reelle Zahl durch zwei Komponenten dargestellt: eine vorzeichenbehaftete Mantisse und ein vorzeichenbehafteter Zehner-Exponent. Nun ist die Dezimalzahl 0,1 gleich einem Faktor von zehn hoch minus eins. Dies ist für den HP48 trivial zu speichern.