python numpy machine epsilon

103

J'essaie de comprendre ce qu'est la machine epsilon. Selon Wikipedia, il peut être calculé comme suit:

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

Cependant, il ne convient que pour les nombres à double précision. Je suis intéressé à le modifier pour prendre en charge également les nombres à simple précision. J'ai lu que numpy peut être utilisé, en particulier la numpy.float32classe. Quelqu'un peut-il aider à modifier la fonction?

Bob
la source
8
Cette fonction est suffisamment générale pour fonctionner avec toutes les précisions. Passez simplement a numpy.float32comme argument à la fonction!
David Zwicker

Réponses:

192

Un moyen plus simple d'obtenir la machine epsilon pour un type de flotteur donné est d'utiliser np.finfo():

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

print(np.finfo(np.float32).eps)
# 1.19209e-07
ali_m
la source
3
juste pour être sûr à 100%, le premier fournit la précision "standard" python des flotteurs innés tandis que le second la précision des flotteurs de numpy?
Charlie Parker
2
notez que la précision standard de numpy est de 64 (dans un ordinateur 64 bits): >>> print(np.finfo(np.float).eps) = 2.22044604925e-16 et >>> print(np.finfo(np.float64).eps) = 2.22044604925e-16
Charlie Parker
2
@CharlieParker J'aurais pu utiliser à la np.floatplace, car c'est juste un alias de la fonction intégrée de Python float. Les flottants Python sont 64 bits (C double) sur presque toutes les plates-formes. floatet ont np.float64donc généralement une précision équivalente, et dans la plupart des cas, vous pouvez les utiliser de manière interchangeable. Cependant, ils ne sont pas identiques - np.float64c'est un type spécifique à numpy, et un np.float64scalaire a des méthodes différentes d'un floatscalaire natif . Comme vous vous en doutez, np.float32c'est un flottant 32 bits.
ali_m
92

Un autre moyen simple d'obtenir epsilon est:

In [1]: 7./3 - 4./3 -1
Out[1]: 2.220446049250313e-16
Ullen
la source
4
Ouais, et pourquoi 8./3 - 5./3 - 1cède-t-il -eps, 4./3 - 1./3 - 1donne zéro et 10./3 - 7./3 - 1rapporte zéro?
Steve Tjoa
20
Ah, la réponse est ici, Problème 3: rstudio-pubs-static.s3.amazonaws.com/ ... En gros, si vous soustrayez la représentation binaire de 4/3 de 7/3, vous obtenez la définition de la machine epsilon. Je suppose donc que cela devrait s'appliquer à n'importe quelle plate-forme.
Steve Tjoa
13
C'est trop ésotérique d'une réponse qui nécessite trop de connaissances de Python et des éléments numpyinternes lorsqu'il existe une numpyfonction existante pour trouver l'epsilon.
Olga Botvinnik
29
Cette réponse ne nécessite aucune connaissance de Python ou des composants internes de numpy.
GuillaumeDufay
5
En effet, il affirme que le lecteur est conscient du fait que Python s'exécute sur des ordinateurs qui n'utilisent pas le calcul de base 3 sous-jacent.
kokociel
17

Cela fonctionnera déjà, comme l'a souligné 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
la source
btw votre fonction augmentera NameErrorsi la condition dans whilesera satisfaite lors de la première vérification, il est donc probablement logique de le faire machine_epsilon = machine_epsilon_last = func(1)dans la première instruction
Azat Ibrakov