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?


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

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

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

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
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.