Python numpy máquina epsilon

103

Estoy tratando de entender qué es la máquina épsilon. Según Wikipedia, se puede calcular de la siguiente manera:

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

Sin embargo, solo es adecuado para números de doble precisión. Estoy interesado en modificarlo para admitir también números de precisión simple. Leí que se puede usar numpy, particularmente numpy.float32class. ¿Alguien puede ayudar a modificar la función?

Beto
fuente
8
Esa función es lo suficientemente general como para trabajar con todas las precisiones. ¡Simplemente pase a numpy.float32como argumento a la función!
David Zwicker

Respuestas:

192

Una forma más fácil de obtener el épsilon de la máquina para un tipo de flotante dado es usar np.finfo():

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

print(np.finfo(np.float32).eps)
# 1.19209e-07
ali_m
fuente
3
sólo para estar 100% seguro, el primero proporciona la precisión "estándar" de python de los flotadores innatos, mientras que el segundo la precisión de los flotadores de numpy.
Charlie Parker
2
tenga en cuenta que la precisión estándar de Numpy es 64 (en una computadora de 64 bits): >>> print(np.finfo(np.float).eps) = 2.22044604925e-16 y >>> print(np.finfo(np.float64).eps) = 2.22044604925e-16
Charlie Parker
2
@CharlieParker podría haber usado en su np.floatlugar, ya que es solo un alias del incorporado de Python float. Los flotadores de Python son de 64 bits (C double) en casi todas las plataformas. floaty, np.float64por lo tanto, suelen tener una precisión equivalente, y para la mayoría de los propósitos puede usarlos indistintamente. Sin embargo, no son idénticos: np.float64es un tipo específico de muchos, y un np.float64escalar tiene métodos diferentes a un floatescalar nativo . Como era de esperar, np.float32es un flotante de 32 bits.
ali_m
92

Otra forma fácil de obtener épsilon es:

In [1]: 7./3 - 4./3 -1
Out[1]: 2.220446049250313e-16
Ullen
fuente
4
Sí, ¿y por qué 8./3 - 5./3 - 1rinde -epsy 4./3 - 1./3 - 1rinde cero y 10./3 - 7./3 - 1rinde cero?
Steve Tjoa
20
Ah, la respuesta está aquí, Problema 3: rstudio-pubs-static.s3.amazonaws.com/… Básicamente, si resta la representación binaria de 4/3 de 7/3, obtiene la definición de máquina épsilon. Así que supongo que esto debería ser válido para cualquier plataforma.
Steve Tjoa
13
Esta es una respuesta demasiado esotérica que requiere demasiado conocimiento de Python y aspectos numpyinternos cuando hay una numpyfunción existente para encontrar el épsilon.
Olga Botvinnik
29
Esta respuesta no requiere ningún conocimiento de Python o componentes internos de Numpy.
GuillaumeDufay
5
De hecho, afirma que el lector está al tanto de que Python se ejecuta en computadoras que no usan computación base 3 subyacente.
kokociel
17

¡Ya funcionará, como señaló 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
fuente
Por cierto, su función aumentará NameErrorsi la condición whilese cumple en la primera verificación, por lo que probablemente tenga sentido hacerlo machine_epsilon = machine_epsilon_last = func(1)en la primera declaración
Azat Ibrakov