Commits

mattip  committed b9f403e

test, implement complex copysign, reciprocal

  • Participants
  • Parent commits 4b6f2ea
  • Branches numpypy-complex2

Comments (0)

Files changed (2)

File pypy/module/micronumpy/test/test_ufuncs.py

     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):
-            return False, msg + 'zero has wrong sign: expected %r, '+ \
-                                       'got %r' % (a, b)
+            return (False, 
+                    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
         assert (signbit([float('nan'), float('-nan'), -float('nan')]) ==
             [False, True, True]).all()    
 
-    def test_reciporocal(self):
-        from _numpypy import array, reciprocal
+    def test_reciprocal(self):
+        from _numpypy import array, reciprocal, complex64, complex128
 
-        reference = [-0.2, float("inf"), float("-inf"), 2.0]
-        a = array([-5.0, 0.0, -0.0, 0.5])
+        inf = float('inf')
+        nan = float('nan')
+        reference = [-0.2, inf, -inf, 2.0, nan]
+        a = array([-5.0, 0.0, -0.0, 0.5, nan])
         b = reciprocal(a)
         for i in range(4):
             assert b[i] == reference[i]
 
+        #complex    
+        fail_at_end = False
+        orig = [2.+4.j, -2.+4.j, 2.-4.j, -2.-4.j, 
+                complex(inf, 3), complex(inf, -3), complex(inf, -inf), 
+                complex(nan, 3), 0+0j, 0-0j]
+        a2 = 2.**2 + 4.**2
+        r = 2. / a2
+        i = 4. / a2
+        cnan = complex(nan, nan)
+        expected = [complex(r, -i), complex(-r, -i), complex(r, i), 
+                    complex(-r, i), 
+                    -0j, 0j, cnan, 
+                    cnan, cnan, cnan]
+        for c, rel_err in ((complex64, 2e-7), (complex128, 2e-15), ):
+            actual = reciprocal(array(orig, dtype=c))
+            for b, a, e in zip(orig, actual, expected):
+                error_message = (
+                    'reciprocal(%r(%r, %r))\n'
+                    'Expected: complex(%r, %r)\n'
+                    'Received: complex(%r, %r)\n'
+                    ) % (c, b.real, b.imag,
+                         e.real, e.imag,
+                         a.real, a.imag)
+                         
+                success,msg = self.rAlmostEqual(e.real, a.real,
+                               rel_err=rel_err, msg=error_message)
+                if not success:
+                    if self.collect_all_failures:
+                        print msg
+                        fail_at_end = True
+                    else:
+                        raise AssertionError(msg)
+                success,msg = self.rAlmostEqual(e.imag, a.imag,
+                               rel_err=rel_err, msg=error_message)
+                if not success:
+                    if self.collect_all_failures:
+                        print msg
+                        fail_at_end = True
+                    else:
+                        raise AssertionError(msg)
+        if fail_at_end:
+            assert False,'at least one test failed, see stdout'
+
+
+
     def test_subtract(self):
         from _numpypy import array, subtract
 
         assert all([math.copysign(1, f(-abs(float("nan")))) == -1 for f in floor, ceil, trunc])
 
     def test_copysign(self):
-        from _numpypy import array, copysign
+        from _numpypy import array, copysign, complex64, complex128
 
         reference = [5.0, -0.0, 0.0, -6.0]
         a = array([-5.0, 0.0, 0.0, 6.0])
         c = copysign(a, b)
         for i in range(4):
             assert c[i] == abs(a[i])
+        for c in complex128, complex64:
+            ref  = complex(5., 5.)
+            a = c(complex(-5., 5.))
+            b = c(complex(0., 0.))
+            assert copysign(a,b) == ref
+            ref = complex(-5., 5.)
+            b = c(complex(-0., 0.))
+            assert copysign(a,b) == ref
+            a = c(complex(float('inf'), float('inf')))
+            ref = complex(-float('inf'), float('inf'))
+            assert copysign(a,b) == ref
 
     def test_exp(self):
         import math
             assert repr(abs(inf_c)) == 'inf'
             assert repr(abs(complex(float('nan'), float('nan')))) == 'nan'
 
-        assert False, 'untested: copysign, reciprocal, sign, floor_div, ' + \
+        assert False, 'untested: sign, floor_div, ' + \
                      'signbit, fabs, fmax, fmin, floor, ceil, trunc, ' + \
                      'exp2, expm1, isnan, isinf, isneginf, isposinf, ' + \
                      'isfinite, radians, degrees, log2, log1p, ' + \
                            float(exp_real), float(exp_imag),
                            flags
                           )
-        tested_funcs=[]
         fail_at_end = False
         for complex_, abs_err in ((np.complex64, 5e-32), (np.complex128, 5e-323), ):
             for id, fn, ar, ai, er, ei, flags in parse_testfile(testcases):
                          expected[0], expected[1],
                          actual[0], actual[1])
                          
-                if not function in tested_funcs:        
-                    print 'fuction',function
-                    tested_funcs.append(function)
                 success,msg = self.rAlmostEqual(expected[0], actual[0],
                                abs_err=real_abs_err, msg=error_message)
                 if not success:

File pypy/module/micronumpy/types.py

     specialize.argtype(1)(func)
     @functools.wraps(func)
     def dispatcher(self, v):
-        try:
-            return self.box_complex(
-                *func(
-                    self,
-                    self.for_computation(self.unbox(v))
-                )
+        return self.box_complex(
+            *func(
+                self,
+                self.for_computation(self.unbox(v))
             )
-        except:
-            import sys
-            print >> sys.stderr, "Could not call",func
-            raise
+        )
     return dispatcher
 
 def raw_unary_op(func):
     def pow(self, v1, v2):
         return rcomplex.c_pow(v1, v2)
 
-    @simple_binary_op
+    @complex_binary_op
     def copysign(self, v1, v2):
-        return math.copysign(v1, v2)
+        return (rfloat.copysign(v1[0], v2[0]),
+               rfloat.copysign(v1[1], v2[1]))
 
     @simple_unary_op
     def sign(self, v):
     #    except ValueError:
     #        return rfloat.NAN
 
-    @simple_unary_op
+    @complex_unary_op
     def reciprocal(self, v):
-        if abs(v) == 0.0:
-            return self.copysign(rfloat.INFINITY, v)
-        return 1.0 / v
+        if math.isinf(v[1]) and math.isinf(v[0]):
+            return rfloat.NAN, rfloat.NAN
+        if math.isinf(v[0]):
+            return (rfloat.copysign(0., v[0]),
+                    rfloat.copysign(0., -v[1]))
+        a2 = v[0]*v[0] + v[1]*v[1]
+        try:
+            return rcomplex.c_div((v[0], -v[1]), (a2, 0.))
+        except ZeroDivisionError:
+            return rfloat.NAN, rfloat.NAN
 
     @simple_unary_op
     def floor(self, v):