Floats sind ungenau
Ich kaufe dieses Argument nicht, denn exakte Zweierpotenzen werden auf den meisten Plattformen genau dargestellt (mit dem zugrunde liegenden IEEE 754 Floating-Point-Format).
Also, wenn wir wirklich wollen, dass log2 einer exakten Zweierpotenz genau ist, können wir das tun.
Ich werde es in Squeak Smalltalk demonstrieren, weil es leicht ist, das Basissystem in dieser Sprache zu ändern, aber die Sprache spielt keine Rolle, Floating-Point-Berechnungen sind universell, und das Python-Objektmodell ist nicht weit von Smalltalk entfernt.
Für das Berechnen des Logarithmus zur Basis n gibt es die Funktion log:, die in Number definiert ist und naiverweise den natürlichen Logarithmus ln verwendet:
log: aNumber
"Gibt den Logarithmus zur Basis aNumber des Empfängers zurück."
^self ln / aNumber ln
self ln
(nimmt den natürlichen Logarithmus des Empfängers) , aNumber ln
und /
sind drei Operationen, die ihr Ergebnis auf die nächste Float-Zahl runden, und diese Rundungsfehler können sich akkumulieren.... Also die naive Implementierung ist anfällig für die von dir beobachteten Rundungsfehler, und ich vermute, dass die Python-Implementierung der Logarithmus-Funktion nicht viel anders ist.
((2 raisedTo: 31) log: 2) = 31.000000000000004
Aber wenn ich die Definition so ändere:
log: aNumber
"Gibt den Logarithmus zur Basis aNumber des Empfängers zurück."
aNumber = 2 ifTrue: [^self log2].
^self ln / aNumber ln
generic liefere ein log2 in der Number-Klasse:
log2
"Gibt den Logarithmus zur Basis 2 des Empfängers zurück."
^self asFloat log2
und diese Verfeinerung in der Float-Klasse:
log2
"Gibt den Logarithmus zur Basis 2 des Empfängers zurück.
Achtet darauf, das genaue Ergebnis für exakte Zweierpotenzen geliefert wird."
^self significand ln / Ln2 + self exponent asFloat
wo Ln2
eine Konstante (2 ln) ist, bekomme ich tatsächlich ein genaues log2 für exakte Zweierpotenzen, weil der Signifikant einer solchen Zahl = 1.0 ist (einschließlich Subnormalität gemäß der Squeak-Exponent/Signifikant-Definition), und 1.0 ln = 0.0
.
Die Implementierung ist ziemlich trivial und sollte ohne Schwierigkeiten in Python übersetzt werden können (wahrscheinlich in der VM); die Laufzeitkosten sind sehr gering, es kommt also nur darauf an, wie wichtig wir diese Funktion finden oder nicht.
Wie ich immer sage, die Tatsache, dass die Ergebnisse von Gleitkommaoperationen auf den nächsten (oder eine beliebige andere) darstellbaren Wert gerundet werden, ist keine Lizenz zum Verschwenden von ulp. Genauigkeit hat einen Preis, sowohl in Bezug auf Laufzeitstrafen als auch auf Implementierungskomplexität, also wird es durch Abwägungen gesteuert.
0 Stimmen
Duplikat der immerwährenden Frage zu Gleitkommazahlen (warum erhalte ich Gleitkommazerros?), kann die beste Duplikatfrage nicht finden, vielleicht kann jemand anderes helfen.
0 Stimmen
Ich möchte darauf hinweisen, dass Python 3 den Gleitkommafehler nicht behoben hat. Stattdessen verwendet die Druckausgabe einen intelligenten Algorithmus, um den beabsichtigten Gleitkommawert anzuzeigen, anstelle des Fehlers.