Ich war ziemlich überrascht, warum ich versuchte, einen Float in C zu multiplizieren (mit GCC 3.2) und dass es nicht so lief, wie ich es erwartet hatte. Als Beispiel:
%Vor%Anzeigen: 31.099998
Ich bin neugierig, wie Floats implementiert werden und warum es zu diesem unerwarteten Verhalten führt.
Als Erstes können Sie Floats multiplizieren. Das Problem, das Sie haben, ist nicht die Multiplikation selbst, sondern die ursprüngliche Nummer, die Sie verwendet haben. Die Multiplikation kann etwas an Genauigkeit verlieren, aber hier hat die ursprüngliche Zahl, die Sie multipliziert haben, mit der verlorenen Präzision begonnen.
Dies ist tatsächlich ein erwartetes Verhalten. float
s werden mittels Binärdarstellung implementiert, was bedeutet, dass Dezimalwerte nicht genau dargestellt werden können.
Weitere Informationen finden Sie unter MSDN .
Sie können auch in die Beschreibung von float sehen hat 6-7 signifikante Ziffern Genauigkeit. In Ihrem Beispiel, wenn Sie 31.099998
auf 7 signifikante Ziffern runden, erhalten Sie 31.1
, so dass es hier immer noch wie erwartet funktioniert.
double
type wäre natürlich genauer, hat aber einen Rundungsfehler aufgrund seiner binären Darstellung, während die Zahl, die Sie geschrieben haben, dezimal ist.
Wenn Sie vollständige Genauigkeit für Dezimalzahlen wünschen, sollten Sie einen Dezimaltyp verwenden. Dieser Typ existiert in Sprachen wie C #. Ссылка
Sie können auch die Darstellung rationaler Zahlen verwenden. Verwenden Sie zwei ganze Zahlen, die Ihnen vollständige Genauigkeit geben, solange Sie die Zahl als eine Division von zwei ganzen Zahlen darstellen können.
Dies funktioniert wie erwartet. Computer haben eine begrenzte Genauigkeit, da sie versuchen, Fließkommawerte aus Ganzzahlen zu berechnen. Dies führt zu Gleitkomma-Ungenauigkeiten.
Die Gleitkomma-Wikipedia -Seite geht viel detaillierter auf die Darstellung und die daraus resultierenden Genauigkeitsprobleme ein als ich hier :)
Interessante Real-World-Randnotiz: das ist teilweise, warum eine Menge Geld Berechnungen werden mit ganzen Zahlen (Cent) gemacht - lassen Sie nicht den Computer Geld mit mangelnder Präzision verlieren! Ich möchte meine $ 0,00001!
Die Zahl 3.11 kann nicht binär dargestellt werden. Der nächste Wert, den Sie mit 24 signifikanten Bits erhalten können, ist 11.0001110000101000111101, was dezimal zu 3.1099998950958251953125 führt.
Wenn Ihre Zahl 3.11 einen Geldbetrag darstellen soll, müssen Sie eine Dezimaldarstellung verwenden.
In den Python-Communities sehen wir die Leute oft überrascht, also gibt es gut getestete und getestete FAQs und Tutorial-Abschnitte zu dem Thema (natürlich werden sie in den Text geschrieben) Begriffe von Python, nicht C, aber da Python-Delegaten Arithmetik auf das zugrunde liegende C und Hardware sowieso schwimmen, gelten alle Beschreibungen der float-Mechanik immer noch).
Es ist natürlich nicht der Fehler der Multiplikation - entferne die Anweisung wo du nb
multiplizierst und du wirst trotzdem ähnliche Probleme sehen.
Aus Wikipedia-Artikel :
Die Tatsache, dass Gleitkommazahlen kann nicht alles real darstellen Zahlen und dieser Fließkommawert Operationen können nicht genau darstellen wahre arithmetische Operationen, führt zu viele überraschende Situationen. Das ist bezogen auf die endliche Präzision mit welche Computer im Allgemeinen repräsentieren Zahlen.
Fließende Punkte sind nicht präzise, weil sie Basis 2 (weil es binär ist: entweder 0 oder 1) anstelle von Basis 10 verwenden. Und die Umwandlung von Basis 2 in die Basis 10 führt, wie bereits erwähnt, zu Rundungspräzisionsproblemen. p>
Tags und Links c floating-point floating-accuracy