[pypy-commit] pypy py3.5: cmath.isclose()
arigo
pypy.commits at gmail.com
Thu Nov 10 04:39:00 EST 2016
Author: Armin Rigo <arigo at tunes.org>
Branch: py3.5
Changeset: r88289:a7657f5b543d
Date: 2016-11-10 10:38 +0100
http://bitbucket.org/pypy/pypy/changeset/a7657f5b543d/
Log: cmath.isclose()
diff --git a/pypy/module/cmath/__init__.py b/pypy/module/cmath/__init__.py
--- a/pypy/module/cmath/__init__.py
+++ b/pypy/module/cmath/__init__.py
@@ -40,6 +40,7 @@
interpleveldefs = {
'pi': 'space.wrap(interp_cmath.pi)',
'e': 'space.wrap(interp_cmath.e)',
+ 'isclose': 'interp_cmath.isclose',
}
interpleveldefs.update(dict([(name, 'interp_cmath.wrapped_' + name)
for name in names_and_docstrings]))
diff --git a/pypy/module/cmath/interp_cmath.py b/pypy/module/cmath/interp_cmath.py
--- a/pypy/module/cmath/interp_cmath.py
+++ b/pypy/module/cmath/interp_cmath.py
@@ -2,8 +2,9 @@
from rpython.rlib.objectmodel import specialize
from rpython.tool.sourcetools import func_with_new_name
from pypy.interpreter.error import oefmt
+from pypy.interpreter.gateway import unwrap_spec
from pypy.module.cmath import names_and_docstrings
-from rpython.rlib import rcomplex
+from rpython.rlib import rcomplex, rfloat
pi = math.pi
e = math.e
@@ -174,3 +175,54 @@
res = c_isfinite(x, y)
return space.newbool(res)
wrapped_isfinite.func_doc = names_and_docstrings['isfinite']
+
+
+ at unwrap_spec(rel_tol=float, abs_tol=float)
+def isclose(space, w_a, w_b, __kwonly__, rel_tol=1e-09, abs_tol=0.0):
+ """isclose(a, b, *, rel_tol=1e-09, abs_tol=0.0) -> bool
+
+Determine whether two complex numbers are close in value.
+
+ rel_tol
+ maximum difference for being considered "close", relative to the
+ magnitude of the input values
+ abs_tol
+ maximum difference for being considered "close", regardless of the
+ magnitude of the input values
+
+Return True if a is close in value to b, and False otherwise.
+
+For the values to be considered close, the difference between them
+must be smaller than at least one of the tolerances.
+
+-inf, inf and NaN behave similarly to the IEEE 754 Standard. That
+is, NaN is not close to anything, even itself. inf and -inf are
+only close to themselves."""
+ ax, ay = space.unpackcomplex(w_a)
+ bx, by = space.unpackcomplex(w_b)
+ #
+ # sanity check on the inputs
+ if rel_tol < 0.0 or abs_tol < 0.0:
+ raise oefmt(space.w_ValueError, "tolerances must be non-negative")
+ #
+ # short circuit exact equality -- needed to catch two infinities of
+ # the same sign. And perhaps speeds things up a bit sometimes.
+ if ax == bx and ay == by:
+ return space.w_True
+ #
+ # This catches 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.
+ # Two infinities of the same sign are caught by the equality check
+ # above.
+ if (rfloat.isinf(ax) or rfloat.isinf(ay) or
+ rfloat.isinf(bx) or rfloat.isinf(by)):
+ return space.w_False
+ #
+ # now do the regular computation
+ # this is essentially the "weak" test from the Boost library
+ diff = c_abs(bx - ax, by - ay)
+ result = ((diff <= rel_tol * c_abs(bx, by) or
+ diff <= rel_tol * c_abs(ax, ay)) or
+ diff <= abs_tol)
+ return space.newbool(result)
diff --git a/pypy/module/cmath/test/test_cmath.py b/pypy/module/cmath/test/test_cmath.py
--- a/pypy/module/cmath/test/test_cmath.py
+++ b/pypy/module/cmath/test/test_cmath.py
@@ -118,6 +118,22 @@
return 2.0
assert cmath.polar(Foo()) == (2, 0)
+ def test_isclose(self):
+ import cmath
+ raises(ValueError, cmath.isclose, 2, 3, rel_tol=-0.5)
+ raises(ValueError, cmath.isclose, 2, 3, abs_tol=-0.5)
+ for z in [0.0, 1.0, 1j,
+ complex("inf"), complex("infj"),
+ complex("-inf"), complex("-infj")]:
+ assert cmath.isclose(z, z)
+ assert not cmath.isclose(complex("infj"), complex("-infj"))
+ assert cmath.isclose(1j, 1j+1e-12)
+ assert not cmath.isclose(1j, 1j+1e-12, rel_tol=1e-13)
+ assert not cmath.isclose(100000j, 100001j)
+ assert cmath.isclose(100000j, 100001j, rel_tol=1e-4)
+ assert cmath.isclose(100000j, 100001j, abs_tol=1.5)
+ assert not cmath.isclose(100000j, 100001j, abs_tol=0.5)
+
def parse_testfile(fname):
"""Parse a file with test values
More information about the pypy-commit
mailing list