floating point in 2.0
Randolph Brown
rgb at panix.com
Sat Jun 9 19:45:17 EDT 2001
In article <9fm9kg05qs at enews1.newsguy.com>,
Alex Martelli <aleaxit at yahoo.com> wrote:
>I recall those darned globals that
>broke my routines when used in somebody else's workspaces as
>the worst blights on an otherwise interesting language
Certainly relatively obscure globals changing the behavior of ==, < and the
like are very dangerous, but comparing floats correctly is non-obvious, so
putting some operations in the default library and pointing to them in the
documentation for floats might be a good way of preventing beginners from
shooting themselves in the foot:
# warning! not terribly tested code follows:
import math
def tolerates(x, y, tol):
"""
are the floating point values x and y within a reasonable tolerance tol of
each other? The tolerance scales with the two numbers (a tolerance of 1E-9
is pretty large around 1, but you need to scale that for numbers in the
millions.)
See Kuth TAoCP v.2 4.2.2
"""
_, ex = math.frexp(x)
_, ey = math.frexp(y)
return math.fabs(x - y) < tol * math.ldexp(1, max(ex, ey))
# really, though, it may make more sense in some cases to specify your
# tolerance as an exponent in base 2, and then you can do some more stuff as
# integer arithmetic:
#
# Warning! no performance checks yet done!
def tolBase2(x, y, tol):
"e.g. tolBase2(x, y, -5) == tolerance(x, y, 2**-5)"
_, ex = math.frexp(x)
_, ey = math.frexp(y)
return math.fabs(x - y) < math.ldexp(1, max(ex+tol, ey+tol))
# maybe also a tolerance that uses ULPs too?
Then we get :
>>> e=1E-9
>>> tolerates(1.0, 1.0, e)
1
>>> tolerates(1.0, 1.1, e)
0
>>> tolerates(1E-10, 1.1e-10, e)
0
>>> tolerates(1e-20, 1.1e-20, e)
0
>>> 1e-20 == 1e-10*1e-10
0
>>> 1e-20
9.9999999999999995e-21
>>> 1e-10*1e-10
1.0000000000000001e-20
>>> tolerates(1e-20, 1e-10*1e-10, e)
1
>>> tolerates(1e-20, 0, e)
1
# note that the reason that last part worked is the encoding of 0:
>>> import math
>>> math.frexp(0)
(0.0, 0)
-Randy
More information about the Python-list
mailing list