python numpy machine epsilon

103

Próbuję zrozumieć, czym jest epsilon maszyny. Według Wikipedii można to obliczyć w następujący sposób:

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

Jednak nadaje się tylko do liczb o podwójnej precyzji. Jestem zainteresowany modyfikacją go, aby obsługiwał również liczby o pojedynczej precyzji. Czytałem, że można użyć numpy, szczególnie numpy.float32class. Czy ktoś może pomóc w modyfikacji funkcji?

Pion
źródło
8
Ta funkcja jest na tyle ogólna, że ​​działa ze wszystkimi szczegółami. Po prostu przekaż numpy.float32jako argument do funkcji!
David Zwicker

Odpowiedzi:

192

Łatwiejszym sposobem uzyskania epsilon maszyny dla danego typu pływaka jest użycie np.finfo():

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

print(np.finfo(np.float32).eps)
# 1.19209e-07
ali_m
źródło
3
tylko po to, aby mieć 100% pewności, pierwsza z nich zapewnia "standardową" precyzję pływaków typu Python, podczas gdy druga zapewnia precyzję pływaków numpy?
Charlie Parker
2
zwróć uwagę, że standardowa dokładność numpy wynosi 64 (w komputerze 64-bitowym): >>> print(np.finfo(np.float).eps) = 2.22044604925e-16 i >>> print(np.finfo(np.float64).eps) = 2.22044604925e-16
Charlie Parker
2
@CharlieParker Mógłbym np.floatzamiast tego użyć , ponieważ jest to tylko alias wbudowanego języka Python float. Python float są 64-bitowe (C double) na prawie wszystkich platformach. floati np.float64dlatego zwykle mają równoważną precyzję i do większości celów można ich używać zamiennie. Jednak nie są identyczne - np.float64jest typem specyficznym dla numpy, a np.float64skalar ma inne metody niż natywny floatskalar. Jak można się spodziewać, np.float32jest to 32-bitowa liczba zmiennoprzecinkowa.
ali_m
92

Innym łatwym sposobem na zdobycie epsilon jest:

In [1]: 7./3 - 4./3 -1
Out[1]: 2.220446049250313e-16
Ullen
źródło
4
Tak, a dlaczego 8./3 - 5./3 - 1wydajności -epsi 4./3 - 1./3 - 1rentowności zera, a 10./3 - 7./3 - 1plony zero?
Steve Tjoa
20
Ach, odpowiedź jest tutaj, problem 3: rstudio-pubs-static.s3.amazonaws.com/… Zasadniczo, jeśli odejmiesz binarną reprezentację 4/3 od 7/3, otrzymasz definicję epsilon maszyny. Więc przypuszczam, że powinno to dotyczyć każdej platformy.
Steve Tjoa
13
Jest to zbyt ezoteryczna odpowiedź, która wymaga zbyt dużej wiedzy na temat Pythona i numpywewnętrznych elementów, gdy istnieje numpyfunkcja, aby znaleźć epsilon.
Olga Botvinnik
29
Ta odpowiedź nie wymaga znajomości języka Python ani numpy wewnętrznych.
GuillaumeDufay
5
Rzeczywiście, zapewnia, że ​​czytelnik jest świadomy tego, że Python działa na komputerach, które nie używają podstawowych obliczeń 3.
kokociel
17

To już zadziała, jak zauważył David!

>>> 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
źródło
btw twoja funkcja wzrośnie, NameErrorjeśli warunek w whilezostanie spełniony przy pierwszym sprawdzeniu, więc prawdopodobnie ma sens to zrobić machine_epsilon = machine_epsilon_last = func(1)w pierwszym oświadczeniu
Azat Ibrakov