Python Numpy Machine Epsilon

103

Ich versuche zu verstehen, was Maschinen-Epsilon ist. Laut Wikipedia kann es wie folgt berechnet werden:

def machineEpsilon(func=float):
    machine_epsilon = func(1)
    while func(1)+func(machine_epsilon) != func(1):
        machine_epsilon_last = machine_epsilon
        machine_epsilon = func(machine_epsilon) / func(2)
    return machine_epsilon_last

Es ist jedoch nur für Zahlen mit doppelter Genauigkeit geeignet. Ich bin daran interessiert, es so zu ändern, dass es auch Zahlen mit einfacher Genauigkeit unterstützt. Ich habe gelesen, dass Numpy verwendet werden kann, insbesondere numpy.float32Klasse. Kann jemand bei der Änderung der Funktion helfen?

Bob
quelle
8
Diese Funktion ist allgemein genug, um mit allen Präzisionen zu arbeiten. Übergeben Sie einfach ein numpy.float32als Argument an die Funktion!
David Zwicker

Antworten:

192

Eine einfachere Möglichkeit, das Maschinen-Epsilon für einen bestimmten Schwimmertyp zu erhalten, ist die Verwendung von np.finfo():

print(np.finfo(float).eps)
# 2.22044604925e-16

print(np.finfo(np.float32).eps)
# 1.19209e-07
ali_m
quelle
3
Um 100% ig sicher zu sein, bietet der erste die "Standard" -Präzision von Python für angeborene Floats, während der zweite die Präzision von Numpys Floats liefert.
Charlie Parker
2
Beachten Sie, dass die Standardgenauigkeit von numpy 64 (in einem 64-Bit-Computer) beträgt: >>> print(np.finfo(np.float).eps) = 2.22044604925e-16 und >>> print(np.finfo(np.float64).eps) = 2.22044604925e-16
Charlie Parker
2
@CharlieParker hätte ich np.floatstattdessen verwenden können, da es nur ein Alias ​​von Pythons eingebautem ist float. Python-Floats sind doubleauf fast allen Plattformen 64-Bit (C ). floatund haben np.float64daher normalerweise die gleiche Präzision, und für die meisten Zwecke können Sie sie austauschbar verwenden. Sie sind jedoch nicht identisch - es np.float64handelt sich um einen numpy-spezifischen Typ, und ein np.float64Skalar hat andere Methoden als ein nativer floatSkalar. Wie zu erwarten np.float32ist ein 32-Bit-Float.
Ali_m
92

Ein weiterer einfacher Weg, um Epsilon zu bekommen, ist:

In [1]: 7./3 - 4./3 -1
Out[1]: 2.220446049250313e-16
Ullen
quelle
4
Ja, und warum tut 8./3 - 5./3 - 1Ausbeute -epsund 4./3 - 1./3 - 1Ausbeuten Null, und die 10./3 - 7./3 - 1Renditen Null?
Steve Tjoa
20
Ah, die Antwort ist hier, Problem 3: rstudio-pubs-static.s3.amazonaws.com/… Wenn Sie die binäre Darstellung von 4/3 von 7/3 subtrahieren, erhalten Sie im Grunde die Definition von Maschinen-Epsilon. Ich nehme an, dies sollte für jede Plattform gelten.
Steve Tjoa
13
Dies ist zu esoterisch für eine Antwort, die zu viel Wissen über Python und numpyInterna erfordert, wenn eine numpyFunktion zum Auffinden des Epsilons vorhanden ist.
Olga Botvinnik
29
Diese Antwort erfordert keine Kenntnisse über Python oder Numpy-Interna.
GuillaumeDufay
5
In der Tat wird behauptet, dass dem Leser bekannt ist, dass Python auf Computern ausgeführt wird, die keine zugrunde liegende Basis-3-Berechnung verwenden.
Kokociel
17

Es wird schon funktionieren, wie David betonte!

>>> def machineEpsilon(func=float):
...     machine_epsilon = func(1)
...     while func(1)+func(machine_epsilon) != func(1):
...         machine_epsilon_last = machine_epsilon
...         machine_epsilon = func(machine_epsilon) / func(2)
...     return machine_epsilon_last
... 
>>> machineEpsilon(float)
2.220446049250313e-16
>>> import numpy
>>> machineEpsilon(numpy.float64)
2.2204460492503131e-16
>>> machineEpsilon(numpy.float32)
1.1920929e-07
Claudiu
quelle
Übrigens wird Ihre Funktion erhöht, NameErrorwenn die Bedingung bei whileder ersten Überprüfung erfüllt ist, so dass es wahrscheinlich sinnvoll ist, dies machine_epsilon = machine_epsilon_last = func(1)in der ersten Anweisung zu tun
Azat Ibrakov