[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