Wie berechne ich den kleinsten Wert, welcher beim Vergleich zweier floats als Unterschied erkannt wird?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
AFoeee
User
Beiträge: 11
Registriert: Montag 22. Januar 2018, 07:00

Hallo,
ich hatte festgestellt, dass der Vergleich von großen float-Werten, deren Differenz gering ist, nicht wie erwartet abläuft. (Siehe hier meine Frage auf stackoverflow.)
Ein Unterschied wird offenbar erst dann bemerkt, wenn er genügend groß ist.

Code: Alles auswählen

import sys

m = sys.float_info.max                        # type 'float'

m == m                                        # True
m < m                                         # False
m > m                                         # False

m == m-1.0                                    # True
m < m-1.0                                     # False
m > m-1.0                                     # False

m == m-1e100                                  # True
m < m-1e100                                   # False
m > m-1e100                                   # False

m == m-1e300                                  # False
m > m-1e300                                   # True
m < m-1e300                                   # False 
Wenn ich die Antwort richtig verstanden habe, beschränkt sich dies nicht nur auf sehr große floats, sondern floats im Allgemeinen:
  • Erst wenn die Differenz zweier Werte größer als ein Mindestwert ist, wird ein Unterschied bemerkt.
  • Dieser Mindestwert hängt von den zu vergleichenden Werten ab.
Nach meinem Verständnis dient für die Bestimmung dieses Mindestwerts sys.float_info.epsilon, wobei es mit der jeweiligen float zu multiplizieren ist.

Code: Alles auswählen

import sys

m = sys.float_info.max                        # type 'float'
eps = sys.float_info.epsilon
# Mindestwert ist 'm*eps'

m == m-(m*(eps/10))                           # True
m == m-(m*eps)                                # False
Wenn m*eps den Mindestwert darstellt, so sollte jeder Wert der kleiner ist eigentlich dazu führen, dass zwei floats als gleich gelten.
Eben das ist aber nicht der Fall!

Code: Alles auswählen

import sys

m = 1000000.0
eps = sys.float_info.epsilon
min_dif = m * eps                             # 0.000000000222044.....

m == m - min_dif                              # False
m == m - (min_dif/2)                          # False
m == m - (min_dif/10)                         # True

m == m - 0.00000000021                       # False
 
Was mache ich falsch?

Obiger Code wurde mit Python 3.5.2 auf einem 64-Bit System ausgeführt.

Mit freundlichen Grüßen
AFoeee
Sirius3
User
Beiträge: 18260
Registriert: Sonntag 21. Oktober 2012, 17:20

Die Antwort auf Stackoverflow ist dahingehend falsch, dass Epsilon die kleinste Zahl ist, die man zu 1 addieren kann, so dass ein von 1 verschiedener Wert in Floatingpoint-Repräsentation entsteht. Du subtrahierst aber, verringerst damit die Anzahl Stellen, so dass mehr Platz für die Repräsentation kleinerer Zahlen bleibt. Die Hexadezimaldarstellung bringt hier Klarheit

Code: Alles auswählen

>>> (1.).hex()
'0x1.0000000000000p+0'
>>> (1+eps).hex()
'0x1.0000000000001p+0'
>>> (1+eps/2).hex()
'0x1.0000000000000p+0'
>>> (1-eps).hex()
'0x1.ffffffffffffep-1'
>>> (1-eps/2).hex()
'0x1.fffffffffffffp-1'
>>> (1-eps/4).hex()
'0x1.0000000000000p+0'
Bei der Subtraktion wird aus dem 2er-Exponent p+0 -> p-1, also ein Bit mehr Platz, so dass auch noch eps/2 subtrahiert werden kann. Erst bei eps/4 reicht die Genauigkeit nicht mehr. Bei der Addition dagegen reicht schon eps/2 um die Änderung nicht mehr darstellen zu können.
Antworten