Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
104 lines (77 sloc) 3.5 KB
#!/usr/bin/env python3
"""
Test implementation for an isclose() function, for possible inclusion in
the Python standard library -- PEP0485
This version has multiple methods in it for experimentation and testing.
The "final" version can be found in isclose.py
This implementation is the result of much discussion on the python-ideas list
in January, 2015:
https://mail.python.org/pipermail/python-ideas/2015-January/030947.html
https://mail.python.org/pipermail/python-ideas/2015-January/031124.html
https://mail.python.org/pipermail/python-ideas/2015-January/031313.html
Copyright: Christopher H. Barker
License: Apache License 2.0 http://opensource.org/licenses/apache2.0.php
"""
import cmath
def isclose(a,
b,
rel_tol=1e-9,
abs_tol=0.0,
method='weak'):
"""
returns True if a is close in value to b. False otherwise
:param a: one of the values to be tested
:param b: the other value to be tested
:param rel_tol=1e-8: The relative tolerance -- the amount of error
allowed, relative to the magnitude of the input
values.
:param abs_tol=0.0: The minimum absolute tolerance level -- useful for
comparisons to zero.
:param method: The method to use. options are:
"asymmetric" : the b value is used for scaling the tolerance
"strong" : The tolerance is scaled by the smaller of
the two values
"weak" : The tolerance is scaled by the larger of
the two values
"average" : The tolerance is scaled by the average of
the two values.
NOTES:
-inf, inf and NaN behave similar to the IEEE 754 standard. That
-is, NaN is not close to anything, even itself. inf and -inf are
-only close to themselves.
Complex values are compared based on their absolute value.
The function can be used with Decimal types, if the tolerance(s) are
specified as Decimals::
isclose(a, b, rel_tol=Decimal('1e-9'))
See PEP-0485 for a detailed description
"""
if method not in ("asymmetric", "strong", "weak", "average"):
raise ValueError('method must be one of: "asymmetric",'
' "strong", "weak", "average"')
if rel_tol < 0.0 or abs_tol < 0.0:
raise ValueError('error tolerances must be non-negative')
if a == b: # short-circuit exact equality
return True
# use cmath so it will work with complex or float
if cmath.isinf(a) or cmath.isinf(b):
# This includes the case of two infinities of opposite sign, or
# one infinity and one finite number. Two infinities of opposite sign
# would otherwise have an infinite relative tolerance.
return False
diff = abs(b - a)
if method == "asymmetric":
return (diff <= abs(rel_tol * b)) or (diff <= abs_tol)
elif method == "strong":
return (((diff <= abs(rel_tol * b)) and
(diff <= abs(rel_tol * a))) or
(diff <= abs_tol))
elif method == "weak":
return (((diff <= abs(rel_tol * b)) or
(diff <= abs(rel_tol * a))) or
(diff <= abs_tol))
elif method == "average":
return ((diff <= abs(rel_tol * (a + b) / 2) or
(diff <= abs_tol)))
else:
raise ValueError('method must be one of:'
' "asymmetric", "strong", "weak", "average"')