python numpy machine epsilon

103

Estou tentando entender o que é epsilon máquina. De acordo com a Wikipedia, pode ser calculado da seguinte forma:

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

No entanto, é adequado apenas para números de precisão dupla. Estou interessado em modificá-lo para suportar também números de precisão simples. Eu li que o numpy pode ser usado, principalmente nas numpy.float32aulas. Alguém pode ajudar a modificar a função?

Prumo
fonte
8
Essa função é geral o suficiente para funcionar com todas as precisões. Apenas passe a numpy.float32como um argumento para a função!
David Zwicker,

Respostas:

192

Uma maneira mais fácil de obter o epsilon da máquina para um determinado tipo de flutuador é usar np.finfo():

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

print(np.finfo(np.float32).eps)
# 1.19209e-07
ali_m
fonte
3
apenas para ter 100% de confiança, o primeiro fornece a precisão python "padrão" de flutuadores inatos, enquanto o segundo fornece a precisão dos flutuadores numpy?
Charlie Parker
2
observe que a precisão padrão da numpy é 64 (em um computador de 64 bits): >>> print(np.finfo(np.float).eps) = 2.22044604925e-16 e >>> print(np.finfo(np.float64).eps) = 2.22044604925e-16
Charlie Parker
2
Eu poderia ter usado @CharlieParker no np.floatlugar, já que é apenas um apelido do Python embutido float. Os floats do Python são de 64 bits (C double) em quase todas as plataformas. floate, np.float64portanto, geralmente têm precisão equivalente e, para a maioria dos propósitos, você pode usá-los de forma intercambiável. No entanto, eles não são idênticos - np.float64é um tipo específico de numpy e um np.float64escalar tem métodos diferentes para um floatescalar nativo . Como você esperaria, np.float32é um float de 32 bits.
ali_m 01 de
92

Outra maneira fácil de obter o epsilon é:

In [1]: 7./3 - 4./3 -1
Out[1]: 2.220446049250313e-16
Ullen
fonte
4
Sim, e por que 8./3 - 5./3 - 1cede -epse 4./3 - 1./3 - 1rende zero e 10./3 - 7./3 - 1rende zero?
Steve Tjoa
20
Ah, a resposta está aqui, Problema 3: rstudio-pubs-static.s3.amazonaws.com/… Basicamente, se você subtrair a representação binária de 4/3 de 7/3, obterá a definição de máquina epsilon. Portanto, suponho que isso deva ser válido para qualquer plataforma.
Steve Tjoa
13
Esta é uma resposta muito esotérica que requer muito conhecimento de Python e numpycomponentes internos quando existe uma numpyfunção existente para encontrar o épsilon.
Olga Botvinnik
29
Esta resposta não requer nenhum conhecimento de Python ou componentes internos numpy.
GuillaumeDufay
5
Na verdade, ele afirma que o leitor está ciente do Python em execução em computadores que não usam computação base 3 subjacente.
kokociel
17

Já vai funcionar, como David apontou!

>>> 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
fonte
btw sua função irá aumentar NameErrorse a condição whilefor satisfeita na primeira verificação, então provavelmente faz sentido fazer machine_epsilon = machine_epsilon_last = func(1)na primeira instrução
Azat Ibrakov