Seite 1 von 1

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

Verfasst: Sonntag 28. Oktober 2018, 19:10
von AFoeee
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

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

Verfasst: Sonntag 28. Oktober 2018, 22:24
von Sirius3
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.