python numpy machine epsilon
Asked Answered
J

3

159

I am trying to understand what is machine epsilon. According to the Wikipedia, it can be calculated as follows:

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

However, it is suitable only for double precision numbers. I am interested in modifying it to support also single precision numbers. I read that numpy can be used, particularly numpy.float32 class. Can anybody help with modifying the function?

Jacquejacquelin answered 2/10, 2013 at 16:3 Comment(1)
That function is general enough to work with all precisions. Just pass a numpy.float32 as an argument to the function!Matt
T
281

An easier way to get the machine epsilon for a given float type is to use np.finfo():

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

print(np.finfo(np.float32).eps)
# 1.19209e-07
Triforium answered 2/10, 2013 at 16:16 Comment(4)
just to be 100% confident, the first one provides python "standard" precision of innate floats while the second one the precision of numpy's floats?Akers
note that numpy's standard accuracy is 64 (in a 64 bit computer): >>> print(np.finfo(np.float).eps) = 2.22044604925e-16 and >>> print(np.finfo(np.float64).eps) = 2.22044604925e-16Akers
@CharlieParker I could have used np.float instead, since it's just an alias of Python's builtin float. Python floats are 64-bit (C double) on almost all platforms. float and np.float64 therefore usually have equivalent precision, and for most purposes you can use them interchangeably. However they aren't identical - np.float64 is a numpy-specific type, and an np.float64 scalar has different methods to a native float scalar. As you'd expect, np.float32 is a 32-bit float.Triforium
or sys.float_info.epsilonPhilosophy
W
122

Another easy way to get epsilon is:

In [1]: 7./3 - 4./3 -1
Out[1]: 2.220446049250313e-16
Withindoors answered 6/8, 2014 at 8:24 Comment(8)
Yeah, and why does 8./3 - 5./3 - 1 yield -eps, and 4./3 - 1./3 - 1 yields zero, and 10./3 - 7./3 - 1 yields zero?Pushup
Ah, the answer is here, Problem 3: rstudio-pubs-static.s3.amazonaws.com/… Basically, if you subtract the binary representation of 4/3 from 7/3, you get the definition of machine epsilon. So I suppose this should hold for any platform.Pushup
This is too esoteric of an answer which requires too much knowledge of Python and numpy internals when there's an existing numpy function to find the epsilon.Benedikt
This answer does not require any knowledge of Python or numpy internals.Hayman
That would need to be abs(7./3 - 4./3 - 1), because otherwise one gets -1.192093e-07 on an ESP32 microcontroller.Percyperdido
Indeed, it asserts that the reader is aware about Python running on computers that aren't using underlying base-3 computation.Sacci
The only reason this is upvoted is because it's cool. But it is a bad answer. I hope no code base has to deal with something looking like this.Ballet
@Ballet disagree. It's a good answer precisely because it avoids usage of a totally unneeded package (numpy) and relies on the precise definition of machine epsilon. Whether it makes the codebase worse depends on how one wraps and names this function and how well-documented it is.Plumley
T
17

It will already work, as David pointed out!

>>> 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
Tivoli answered 2/10, 2013 at 16:12 Comment(1)
btw your function will raise NameError if condition in while will be satisfied on the first check, so it probably makes sense to do machine_epsilon = machine_epsilon_last = func(1) in the first statementRecession

© 2022 - 2024 — McMap. All rights reserved.