[pypy-commit] pypy numpypy-complex2: test and fix power(), try and fail to pass on cpython numpy

mattip noreply at buildbot.pypy.org
Fri Sep 14 15:18:42 CEST 2012


Author: mattip <matti.picus at gmail.com>
Branch: numpypy-complex2
Changeset: r57346:461cdf93d12a
Date: 2012-09-14 10:31 +0300
http://bitbucket.org/pypy/pypy/changeset/461cdf93d12a/

Log:	test and fix power(), try and fail to pass on cpython numpy

diff --git a/pypy/module/micronumpy/interp_ufuncs.py b/pypy/module/micronumpy/interp_ufuncs.py
--- a/pypy/module/micronumpy/interp_ufuncs.py
+++ b/pypy/module/micronumpy/interp_ufuncs.py
@@ -575,8 +575,10 @@
             ("arccosh", "arccosh", 1, {"promote_to_float": True}),
             ("arctanh", "arctanh", 1, {"promote_to_float": True}),
 
-            ("radians", "radians", 1, {"promote_to_float": True}),
-            ("degrees", "degrees", 1, {"promote_to_float": True}),
+            ("radians", "radians", 1, {"promote_to_float": True,
+                                       "allow_complex": False}),
+            ("degrees", "degrees", 1, {"promote_to_float": True,
+                                       "allow_complex": False}),
 
             ("log", "log", 1, {"promote_to_float": True}),
             ("log2", "log2", 1, {"promote_to_float": True}),
diff --git a/pypy/module/micronumpy/test/complex_testcases.txt b/pypy/module/micronumpy/test/complex_testcases.txt
--- a/pypy/module/micronumpy/test/complex_testcases.txt
+++ b/pypy/module/micronumpy/test/complex_testcases.txt
@@ -1638,7 +1638,7 @@
 exp1019 exp inf 4.2 -> -inf -inf
 exp1020 exp inf 5.6 -> inf -inf
 exp1021 exp inf 7.0 -> inf inf
-exp1022 exp -inf inf -> nan nan         ignore-real-sign ignore-imag-sign
+exp1022 exp -inf inf -> 0 0         ignore-real-sign ignore-imag-sign
 exp1023 exp inf inf -> nan nan          invalid ignore-real-sign
 exp1024 exp -inf nan -> nan nan         ignore-real-sign ignore-imag-sign
 exp1025 exp inf nan -> nan nan          ignore-real-sign
diff --git a/pypy/module/micronumpy/test/test_ufuncs.py b/pypy/module/micronumpy/test/test_ufuncs.py
--- a/pypy/module/micronumpy/test/test_ufuncs.py
+++ b/pypy/module/micronumpy/test/test_ufuncs.py
@@ -1,8 +1,61 @@
 
 from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
+from math import isnan, isinf, copysign
+from sys import version_info, builtin_module_names
 
 from pypy.conftest import option
 
+def rAlmostEqual(a, b, rel_err = 2e-15, abs_err = 5e-323, msg='', isnumpy=False):
+    """Fail if the two floating-point numbers are not almost equal.
+
+    Determine whether floating-point values a and b are equal to within
+    a (small) rounding error.  The default values for rel_err and
+    abs_err are chosen to be suitable for platforms where a float is
+    represented by an IEEE 754 double.  They allow an error of between
+    9 and 19 ulps.
+    """
+
+    # special values testing
+    if isnan(a):
+        if isnan(b):
+            return True,''
+        raise AssertionError(msg + '%r should be nan' % (b,))
+
+    if isinf(a):
+        if a == b:
+            return True,''
+        raise AssertionError(msg + 'finite result where infinity expected: '+ \
+                          'expected %r, got %r' % (a, b))
+
+    # if both a and b are zero, check whether they have the same sign
+    # (in theory there are examples where it would be legitimate for a
+    # and b to have opposite signs; in practice these hardly ever
+    # occur).
+    if not a and not b and not isnumpy:
+        # only check it if we are running on top of CPython >= 2.6
+        if version_info >= (2, 6) and copysign(1., a) != copysign(1., b):
+            raise AssertionError( msg + \
+                    'zero has wrong sign: expected %r, got %r' % (a, b))
+
+    # if a-b overflows, or b is infinite, return False.  Again, in
+    # theory there are examples where a is within a few ulps of the
+    # max representable float, and then b could legitimately be
+    # infinite.  In practice these examples are rare.
+    try:
+        absolute_error = abs(b-a)
+    except OverflowError:
+        pass
+    else:
+        # test passes if either the absolute error or the relative
+        # error is sufficiently small.  The defaults amount to an
+        # error of between 9 ulps and 19 ulps on an IEEE-754 compliant
+        # machine.
+        if absolute_error <= max(abs_err, rel_err * abs(a)):
+            return True,''
+    raise AssertionError(msg + \
+            '%r and %r are not sufficiently close, %g > %g' %\
+            (a, b, absolute_error, max(abs_err, rel_err*abs(a))))
+
 class AppTestUfuncs(BaseNumpyAppTest):
     def setup_class(cls):
         import os
@@ -13,6 +66,12 @@
         cls.w_testcases64 = cls.space.wrap(fname64)
         cls.w_runAppDirect = cls.space.wrap(option.runappdirect)
         cls.w_isWindows = cls.space.wrap(os.name == 'nt')
+        def cls_rAlmostEqual(self, *args, **kwargs):
+            if '__pypy__' not in builtin_module_names:
+                kwargs['isnumpy'] = True
+            return rAlmostEqual(*args, **kwargs)
+        cls.w_rAlmostEqual = cls.space.wrap(cls_rAlmostEqual)
+
 
     def test_ufunc_instance(self):
         from _numpypy import add, ufunc
@@ -403,11 +462,14 @@
             assert b[i] == res
 
     def test_exp2(self):
-        import math
+        import math, cmath
         from _numpypy import array, exp2
+        inf = float('inf')
+        ninf = -float('inf')
+        nan = float('nan')
+        cmpl = complex
 
-        a = array([-5.0, -0.0, 0.0, 2, 12345678.0, float("inf"),
-                   -float('inf'), -12343424.0])
+        a = array([-5.0, -0.0, 0.0, 2, 12345678.0, inf, ninf, -12343424.0])
         b = exp2(a)
         for i in range(len(a)):
             try:
@@ -417,7 +479,24 @@
             assert b[i] == res
 
         assert exp2(3) == 8
-        assert math.isnan(exp2(float("nan")))
+        assert math.isnan(exp2(nan))
+
+        a = array([cmpl(-5., 0), cmpl(-5., -5.), cmpl(-5., 5.),
+                   cmpl(0., -5.), cmpl(0., 0.), cmpl(0., 5.),
+                   cmpl(-0., -5.), cmpl(-0., 0.), cmpl(-0., 5.),
+                   cmpl(-0., -0.), cmpl(inf, 0.), cmpl(inf, 5.),
+                   cmpl(inf, -0.), cmpl(ninf, 0.), cmpl(ninf, 5.),
+                   cmpl(ninf, -0.), cmpl(ninf, inf), cmpl(inf, inf),
+                   cmpl(ninf, ninf), cmpl(5., inf), cmpl(5., ninf),
+                   cmpl(nan, 5.), cmpl(5., nan), cmpl(nan, nan),
+                 ])
+        b = exp2(a)
+        for i in range(len(a)):
+            try:
+                res = cmath.pow(2,a[i])
+            except OverflowError:
+                res = cmpl(inf, nan)
+            assert b[i] == res
 
     def test_expm1(self):
         import math
@@ -614,6 +693,8 @@
         for i in range(len(a)):
             assert b[i] == math.radians(a[i])
 
+        raises(TypeError, radians, complex(90,90))
+
     def test_deg2rad(self):
         import math
         from _numpypy import deg2rad, array
@@ -627,6 +708,8 @@
         for i in range(len(a)):
             assert b[i] == math.radians(a[i])
 
+        raises(TypeError, deg2rad, complex(90,90))
+
     def test_degrees(self):
         import math
         from _numpypy import degrees, array
@@ -640,6 +723,8 @@
         for i in range(len(a)):
             assert b[i] == math.degrees(a[i])
 
+        raises(TypeError, degrees, complex(90,90))
+
     def test_rad2deg(self):
         import math
         from _numpypy import rad2deg, array
@@ -653,6 +738,8 @@
         for i in range(len(a)):
             assert b[i] == math.degrees(a[i])
 
+        raises(TypeError, rad2deg, complex(90,90))
+
     def test_reduce_errors(self):
         from _numpypy import sin, add
 
@@ -835,6 +922,43 @@
         assert log1p(float('inf')) == float('inf')
         assert (log1p([0, 1e-50, math.e - 1]) == [0, 1e-50, 1]).all()
 
+    def test_power_complex(self):
+        import math, cmath
+        inf = float('inf')
+        ninf = -float('inf')
+        nan = float('nan')
+        cmpl = complex
+        from _numpypy import power, array, complex128, complex64
+        for c,rel_err in ((complex128, 5e-323), (complex64, 1e-7)):
+            a = array([cmpl(-5., 0), cmpl(-5., -5.), cmpl(-5., 5.),
+                       cmpl(0., -5.), cmpl(0., 0.), cmpl(0., 5.),
+                       cmpl(-0., -5.), cmpl(-0., 0.), cmpl(-0., 5.),
+                       cmpl(-0., -0.), cmpl(inf, 0.), cmpl(inf, 5.),
+                       cmpl(inf, -0.), cmpl(ninf, 0.), cmpl(ninf, 5.),
+                       cmpl(ninf, -0.), cmpl(ninf, inf), cmpl(inf, inf),
+                       cmpl(ninf, ninf), cmpl(5., inf), cmpl(5., ninf),
+                       cmpl(nan, 5.), cmpl(5., nan), cmpl(nan, nan),
+                     ], dtype=c)
+            got_err = False
+            for p in (3, -1, 10000, 2.3, -10000, 10+3j):
+                b = power(a, p)
+                for i in range(len(a)):
+                    r = a[i]**p
+                    msg = 'result of %r(%r)**%r got %r expected %r\n ' % \
+                            (c,a[i], p, b[i], r)
+                    try:        
+                        t1 = float(r.real)        
+                        t2 = float(b[i].real)        
+                        self.rAlmostEqual(t1, t2, rel_err=rel_err, msg=msg)
+                        t1 = float(r.imag)        
+                        t2 = float(b[i].imag)        
+                        self.rAlmostEqual(t1, t2, rel_err=rel_err, msg=msg)
+                    except AssertionError as e:
+                        print e.message
+                        got_err = True
+            if got_err:
+                raise AssertionError('Errors were printed to stdout')
+
     def test_power_float(self):
         import math
         from _numpypy import power, array
@@ -1050,64 +1174,14 @@
         assert False, 'untested: ' + \
                      'numpy.real. numpy.imag' + \
                      'exp2, expm1, ' + \
-                     'radians, degrees, log2, log1p, ' + \
+                     'log2, log1p, ' + \
                      'logaddexp, npy_log2_1p, logaddexp2'
 
     def test_complex_math(self):
         if self.isWindows:
             skip('windows does not support c99 complex')
         import  _numpypy as np
-        from math import isnan, isinf, copysign
-        from sys import version_info
-
-        def rAlmostEqual(a, b, rel_err = 2e-15, abs_err = 5e-323, msg=''):
-            """Fail if the two floating-point numbers are not almost equal.
-
-            Determine whether floating-point values a and b are equal to within
-            a (small) rounding error.  The default values for rel_err and
-            abs_err are chosen to be suitable for platforms where a float is
-            represented by an IEEE 754 double.  They allow an error of between
-            9 and 19 ulps.
-            """
-
-            # special values testing
-            if isnan(a):
-                if isnan(b):
-                    return True,''
-                raise AssertionError(msg + '%r should be nan' % (b,))
-
-            if isinf(a):
-                if a == b:
-                    return True,''
-                raise AssertionError(msg + 'finite result where infinity expected: '+ \
-                                  'expected %r, got %r' % (a, b))
-
-            # if both a and b are zero, check whether they have the same sign
-            # (in theory there are examples where it would be legitimate for a
-            # and b to have opposite signs; in practice these hardly ever
-            # occur).
-            if not a and not b:
-                # only check it if we are running on top of CPython >= 2.6
-                if version_info >= (2, 6) and copysign(1., a) != copysign(1., b):
-                    raise AssertionError( msg + \
-                            'zero has wrong sign: expected %r, got %r' % (a, b))
-
-            # if a-b overflows, or b is infinite, return False.  Again, in
-            # theory there are examples where a is within a few ulps of the
-            # max representable float, and then b could legitimately be
-            # infinite.  In practice these examples are rare.
-            try:
-                absolute_error = abs(b-a)
-            except OverflowError:
-                pass
-            else:
-                # test passes if either the absolute error or the relative
-                # error is sufficiently small.  The defaults amount to an
-                # error of between 9 ulps and 19 ulps on an IEEE-754 compliant
-                # machine.
-                if absolute_error <= max(abs_err, rel_err * abs(a)):
-                    return True,''
-            raise AssertionError(msg + '%r and %r are not sufficiently close' % (a, b))
+        rAlmostEqual = self.rAlmostEqual
 
         def parse_testfile(fname):
             """Parse a file with test values
@@ -1172,8 +1246,10 @@
                     ) % (id, fn, complex_, ar, ai,
                          expected[0], expected[1],
                          actual[0], actual[1])
-                         
-                rAlmostEqual(expected[0], actual[0],
+    
+                # since rAlmostEqual is a wrapped function,
+                # convert arguments to avoid boxed values
+                rAlmostEqual(float(expected[0]), float(actual[0]),
                                abs_err=real_abs_err, msg=error_message)
-                rAlmostEqual(expected[1], actual[1],
+                rAlmostEqual(float(expected[1]), float(actual[1]),
                                    msg=error_message)
diff --git a/pypy/module/micronumpy/types.py b/pypy/module/micronumpy/types.py
--- a/pypy/module/micronumpy/types.py
+++ b/pypy/module/micronumpy/types.py
@@ -1154,7 +1154,15 @@
 
     @complex_binary_op
     def pow(self, v1, v2):
-        return rcomplex.c_pow(v1, v2)
+        if not isfinite(v1[0]) or not isfinite(v1[1]):
+            return rfloat.NAN, rfloat.NAN
+        try:
+            return rcomplex.c_pow(v1, v2)
+        except ZeroDivisionError:
+            return rfloat.NAN, rfloat.NAN
+        except OverflowError:
+            return rfloat.INFINITY, rfloat.INFINITY
+
 
     #complex copysign does not exist in numpy
     #@complex_binary_op
@@ -1249,9 +1257,10 @@
                 return rfloat.INFINITY, 0.0
             return rfloat.INFINITY, rfloat.NAN
 
+    @complex_unary_op
     def exp2(self, v):
         try:
-            return self.pow(2, v)
+            return rcomplex.c_pow((2,0), v2)
         except OverflowError:
             return rfloat.INFINITY, rfloat.NAN
 
@@ -1382,14 +1391,14 @@
     def isfinite(self, v):
         return isfinite(v[0]) and isfinite(v[1])
 
-    @simple_unary_op
-    def radians(self, v):
-        return v * degToRad
-    deg2rad = radians
+    #@simple_unary_op
+    #def radians(self, v):
+    #    return v * degToRad
+    #deg2rad = radians
 
-    @simple_unary_op
-    def degrees(self, v):
-        return v / degToRad
+    #@simple_unary_op
+    #def degrees(self, v):
+    #    return v / degToRad
 
     @complex_unary_op
     def log(self, v):


More information about the pypy-commit mailing list