Warum 1.0f + 0.0000000171785715f kehrt 1f?
-
22-08-2019 - |
Frage
Nach einer Stunde versucht, einen Fehler in meinem Code zu finden habe ich endlich den Grund. Ich habe versucht, einen sehr kleinen Schwimmer bis 1f hinzufügen, aber nichts geschieht. Bei dem Versuch, herauszufinden, warum ich fand, dass das Hinzufügen, dass kleine Schwimmer 0f perfekt funktioniert.
Warum ist das passiert? Ist dies mit ‚Größenordnungen‘ zu tun? Gibt es eine Abhilfe für dieses Problem?
Vielen Dank im Voraus.
Edit:
Die Umstellung auf doppelte Genauigkeit oder dezimal ist keine Option im Moment.
Lösung
Da Präzision für eine mit einfacher Genauigkeit (32 Bit) Gleitkommawert ist etwa 7 Ziffern nach dem Dezimalpunkt. Was bedeutet, dass der Wert der Sie hinzufügen, ist im wesentlichen Null ist, zumindest wenn sie 1
hinzugefügt. Der Wert selbst kann jedoch in einem Schwimmer mühelos gespeichert, da der Exponent in diesem Fall klein ist. Aber, um es erfolgreich in dem 1
Sie die Exponenten der größeren Anzahl verwenden ... und dann die Ziffern nach den Nullen verschwinden in Runden.
Sie können double
verwenden, wenn Sie mehr Präzision benötigen. Performance-weise dies sollte keinen Unterschied auf der heutigen Hardware machen und Speicher wird oft auch nicht so eingeschränkt, dass Sie denken über jede einzelne Variable.
EDIT: Wie Sie festgestellt, dass double
Verwendung ist keine Option, die Sie verwenden können Kahan Summierung , wie akuhn wies in einem Kommentar aus.
kann eine andere Option, um Vermittler Berechnungen in doppelter Genauigkeit durchführen und danach wieder zu gieße float
. Dies wird nur helfen, aber wenn es ein paar mehr Operationen als nur das Hinzufügen eine sehr kleine Zahl zu einem größeren.
Andere Tipps
Dies geschieht wahrscheinlich, weil die Anzahl der Ziffern der Präzision in einem Schwimmer konstant ist, aber der Exponent kann natürlich variieren.
Das bedeutet, dass, obwohl Sie Ihre kleine Zahl auf 0 hinzufügen können, können Sie es nicht zu einer Reihe hinzuzufügen erwarten, die einen Exponenten von 0 verschieden ist, da es einfach nicht genug Stellen genau links sein.
Sie sollten lesen Was jeder Informatiker wissen sollten über Gleitkommaarithmetik .
Es sieht aus wie es hat etwas mit Gleitkommagenauigkeit zu tun. Wenn ich Sie wäre, würde ich eine andere Art, wie decimal
verwenden. Das sollte Präzision Fehler beheben.
Mit float
, man bekommt nur eine Genauigkeit von etwa sieben Ziffern . Also Ihr number'll in 1f gerundet. Wenn Sie eine solche Nummer speichern möchten, verwenden Sie double
statt
Neben der akzeptierte Antwort: Wenn Sie viele kleine Anzahl und einige größere müssen zusammenzufassen, sollten Sie Kahan Summieren .
Wenn die Leistung ist ein Problem (weil Sie nicht double
verwenden können), dann binäre Skalierung / Fest Punkt kann eine Option sein. float
s werden als ganze Zahlen gespeichert, sondern von einer großen Anzahl (sagen wir, 2 ^ 16) skaliert. Zwischen Arithmetik mit (relativ schnell) Integer-Operationen durchgeführt. Die endgültige Antwort kann am Ende zu Gleitkomma umgewandelt zurück, um mit dem Skalierungsfaktor dividiert wird.
Dies ist oft getan, wenn der Zielprozessor eine Hardware fehlt Gleitkommaeinheit.
Sie sind mit dem f-Suffix auf Literale, die diesen Schwimmer statt verdoppelt machen. So Ihr sehr kleiner Schwimmer wird in dem größeren Schwimmer verschwinden.