2013-10-02 13 views
45

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

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 podwójnej precyzji. Interesuje mnie modyfikowanie go tak, aby obsługiwał również liczby pojedynczej precyzji. Czytałem, że można używać numpy, szczególnie klasy numpy.float32. Czy ktokolwiek może pomóc w modyfikacji funkcji?

+5

Ta funkcja jest ogólnie wystarczy, aby pracować ze wszystkimi szczegółami. Wystarczy przekazać 'numpy.float32' jako argument do funkcji! –

Odpowiedz

93

Łatwiejszy sposób, aby uzyskać epsilon maszynowy dla danego typu float jest użycie np.finfo():

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

print(np.finfo(np.float32).eps) 
# 1.19209e-07 
+0

żeby być w 100% pewnym, pierwszy zapewnia Pythona "standardową" precyzję wrodzonych pływaków, a drugi precyzję pływaków numpy? –

+0

pamiętać, że średnia dokładność NumPy jest 64 (w komputerze 64-bitowy): '>>> print (np.finfo (np.float) .eps) = 2.22044604925e-16' i ' >> > print (np.finfo (np.float64) .eps) = 2.22044604925e-16' –

+0

@CharlieParker Mogłem zamiast tego użyć 'np.float', ponieważ jest to po prostu alias wbudowanego w Pythona' float'. Pythonowe pływaki są 64-bitowe (C "podwójne") na prawie wszystkich platformach. 'float' i' np.float64' mają zwykle równoważną dokładność, a do większości celów można ich używać zamiennie. Jednak nie są one identyczne - 'np.float64' jest typem specyficznym dla numpy, a skalar' np.float64' ma różne metody do natywnego skalaru 'float'. Jak można się spodziewać, 'np.float32' jest 32-bitowym floatem. –

12

Już będzie działać, jak zauważył Dawid!

>>> 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 
57

Kolejny łatwy sposób uzyskać Epsilon to:

In [1]: 7./3 - 4./3 -1 
Out[1]: 2.220446049250313e-16 
+10

To interesujące - czy mógłbyś wyjaśnić, dlaczego to działa? –

+2

Tak, i dlaczego '8/3 - 5./3 - 1' daje' -eps', a '4./3 - 1./3 - 1' daje zero i' 10./3 - 7 ./3 - 1' daje zero? –

+14

Ah, odpowiedź jest tutaj, Problem 3: http://rstudio-pubs-static.s3.amazonaws.com/13303_daf1916bee714161ac78d3318de808a9.html Zasadniczo, jeśli odejmiesz binarną reprezentację 4/3 z 7/3, otrzymasz definicja epsilon maszyny. Tak więc przypuszczam, że powinno to dotyczyć każdej platformy. –