Commits

mattip committed 7f7b6d5

start to test binary complex functions in rcomplex

  • Participants
  • Parent commits cce47db
  • Branches numpypy-complex2

Comments (0)

Files changed (3)

File pypy/rlib/test/rcomplex_testcases.txt

--- Testcases for functions in cmath.
+-- Testcases for functions in rcomplex, copied from cpython's cmath.
 --
 -- Each line takes the form:
 --

File pypy/rlib/test/rcomplex_testcases2.txt

+-- Testcases for functions in rcomplex, based on syntax of cpython's
+-- cmath tests.
+--
+-- Each line takes the form:
+--
+-- <testid> <function> <input_value> [<input_value>] -> <output_value> <flags>
+--
+-- where:
+--
+--   <testid> is a short name identifying the test,
+--
+--   <function> is the function to be tested (exp, cos, asinh, ...),
+--
+--   <input_value> is either a pair or a quad of values separated by whitespace
+--     representing real and imaginary parts of a complex number, and
+--
+--   <output_value> is the expected (ideal) output value, again
+--     represented as a pair of values.
+--
+--   The values used may be a hex representation of a float beginning with
+--   '0x' or '0X' or a decimal representation of a float.
+--
+--   <flags> is a list of the floating-point flags required by C99
+--
+-- The possible flags are:
+--
+--   divide-by-zero : raised when a finite input gives a
+--     mathematically infinite result.
+--
+--   overflow : raised when a finite input gives a finite result whose
+--     real or imaginary part is too large to fit in the usual range
+--     of an IEEE 754 double.
+--
+--   invalid : raised for invalid inputs.
+--
+--   ignore-real-sign : indicates that the sign of the real part of
+--     the result is unspecified; if the real part of the result is
+--     given as inf, then both -inf and inf should be accepted as
+--     correct.
+--
+--   ignore-imag-sign : indicates that the sign of the imaginary part
+--     of the result is unspecified.
+--
+-- Flags may appear in any order.
+--
+-- Lines beginning with '--' (like this one) start a comment, and are
+-- ignored.  Blank lines, or lines containing only whitespace, are also
+-- ignored.
+--
+-- These tests are designed to excercise interesting values of functions,
+-- includind special values (+inf, -inf, nan, +0, -0, min_mantissa,
+-- min_exponent, max_mantissa, max_exponent) in both input and output,
+-- random values, and any branch cuts implicit in the function
+-- (non-continuities in function value)
+
+ 
+-----------------------
+-- pow: power --
+-----------------------
+-- if x is 1.0, result is 1.0
+pow0000 pow 1.0 0.0 0.0 0.0 -> 1.0 0.0
+pow0001 pow 1.0 0.0 2.0 0.0 -> 1.0 0.0
+pow0002 pow 1.0 0.0 0.0 2.0 -> 1.0 0.0
+pow0003 pow 1.0 0.0 2.0 2.0 -> 1.0 0.0
+pow0004 pow 1.0 0.0 inf 0.0 -> 1.0 0.0
+pow0005 pow 1.0 0.0 0.0 inf -> 1.0 0.0
+pow0006 pow 1.0 0.0 inf inf -> 1.0 0.0
+pow0007 pow 1.0 0.0 -inf 0.0 -> 1.0 0.0
+pow0008 pow 1.0 0.0 0.0 -inf -> 1.0 0.0
+pow0009 pow 1.0 0.0 -inf -inf -> 1.0 0.0
+pow0010 pow 1.0 0.0 nan 0.0 -> 1.0 0.0
+pow0011 pow 1.0 0.0 0.0 nan -> 1.0 0.0
+pow0012 pow 1.0 0.0 nan nan -> 1.0 0.0
+-- if y is 0.0, result is 1.0
+pow0020 pow 0.0 0.0  1.0 0.0 -> 1.0 0.0
+pow0021 pow 2.0 0.0  1.0 0.0 -> 1.0 0.0
+pow0022 pow 0.0 2.0  1.0 0.0 -> 1.0 0.0
+pow0023 pow 2.0 2.0  1.0 0.0 -> 1.0 0.0
+pow0024 pow inf 0.0  1.0 0.0 -> 1.0 0.0
+pow0025 pow 0.0 inf  1.0 0.0 -> 1.0 0.0
+pow0026 pow inf inf  1.0 0.0 -> 1.0 0.0
+pow0027 pow -inf 0.0 1.0 0.0 -> 1.0 0.0
+pow0028 pow 0.0 -inf 1.0 0.0 -> 1.0 0.0
+pow0029 pow -inf -inf 1.0 0.0 -> 1.0 0.0
+pow0030 pow nan 0.0  1.0 0.0 -> 1.0 0.0
+pow0031 pow 0.0 nan  1.0 0.0 -> 1.0 0.0
+pow0032 pow nan nan  1.0 0.0 -> 1.0 0.0

File pypy/rlib/test/test_rcomplex.py

 
 import pypy.rlib.rcomplex as c
 from pypy.rlib.rfloat import copysign, isnan, isinf
-import os, sys, math
+import os, sys, math, struct
 
 
 def test_add():
         ]:
             assert c.c_mul(c1, c2) == result
 
+def parse_testfile2(fname):
+    """Parse a file with test values
+
+    Empty lines or lines starting with -- are ignored
+    yields id, fn, arg1_real, arg1_imag, arg2_real, arg2_imag,
+    exp_real, exp_imag where numbers in file may be expressed as     floating point or hex
+    """
+    fname = os.path.join(os.path.dirname(__file__), fname)
+    with open(fname) as fp:
+        for line in fp:
+            # skip comment lines and blank lines
+            if line.startswith('--') or not line.strip():
+                continue
+
+            lhs, rhs = line.split('->')
+            lhs_pieces = lhs.split()
+            rhs_pieces = rhs.split()
+            for i in range(2, len(lhs_pieces)):
+                if lhs_pieces[i].lower().startswith('0x'):
+                    lhs_pieces[i] = struct.unpack('d',
+                        struct.pack('q',int(lhs_pieces[i])))
+                else:
+                    lhs_pieces[i] = float(lhs_pieces[i])
+            for i in range(2):
+                if rhs_pieces[i].lower().startswith('0x'):
+                    rhs_pieces[i] = struct.unpack('d',
+                        struct.pack('l',int(rhs_pieces[i])))
+                else:
+                    rhs_pieces[i] = float(rhs_pieces[i])
+            #id, fn, arg1_real, arg1_imag arg2_real, arg2_imag = 
+            #exp_real, exp_imag = rhs_pieces[0], rhs_pieces[1]
+            flags = rhs_pieces[2:]
+            id_f, fn = lhs_pieces[:2]
+            if len(lhs_pieces)>4:
+                args = (lhs_pieces[2:4], lhs_pieces[4:])
+            else:
+                args = lhs_pieces[2:]
+            yield id_f, fn, args, rhs_pieces[:2], flags
+
+
+
 def parse_testfile(fname):
     """Parse a file with test values
 
                    flags
                   )
 
+def args_to_str(args):
+    if isinstance(args[0],(list, tuple)):
+        return '(complex(%r, %r), complex(%r, %r))' % \
+             (args[0][0], args[0][1], args[1][0], args[1][1])
+    else:
+        return '(complex(%r, %r))' % (args[0], args[1])
+            
 def rAssertAlmostEqual(a, b, rel_err = 2e-15, abs_err = 5e-323, msg=''):
     """Fail if the two floating-point numbers are not almost equal.
 
     #if not float.__getformat__("double").startswith("IEEE"):
     #    return
 
-    for id, fn, ar, ai, er, ei, flags in parse_testfile('rcomplex_testcases.txt'):
-        arg = (ar, ai)
-        expected = (er, ei)
+    for id, fn, arg, expected, flags in parse_testfile2('rcomplex_testcases.txt'):
         function = getattr(c, 'c_' + fn)
         #
         if 'divide-by-zero' in flags or 'invalid' in flags:
                 continue
             else:
                 raise AssertionError('ValueError not raised in test '
-                                     '%s: %s(complex(%r, %r))' % (id, fn,
-                                                                  ar, ai))
+                          '%s: %s%s' % (id, fn, args_to_str(arg)))
         if 'overflow' in flags:
             try:
                 actual = function(*arg)
                 continue
             else:
                 raise AssertionError('OverflowError not raised in test '
-                                     '%s: %s(complex(%r, %r))' % (id, fn,
-                                                                  ar, ai))
+                          '%s: %s%s' % (id, fn, args_to_str(arg)))
         actual = function(*arg)
 
         if 'ignore-real-sign' in flags:
             real_abs_err = 5e-323
 
         error_message = (
-            '%s: %s(complex(%r, %r))\n'
+            '%s: %s%s\n'
             'Expected: complex(%r, %r)\n'
             'Received: complex(%r, %r)\n'
-            ) % (id, fn, ar, ai,
+            ) % (id, fn, args_to_str(arg),
                  expected[0], expected[1],
                  actual[0], actual[1])
 
                            abs_err=real_abs_err,
                            msg=error_message)
         rAssertAlmostEqual(expected[1], actual[1],
+                           abs_err=real_abs_err,
                            msg=error_message)
+
+    for id, fn, a, expected, flags in parse_testfile2('rcomplex_testcases2.txt'):
+        function = getattr(c, 'c_' + fn)
+        #
+        if 'divide-by-zero' in flags or 'invalid' in flags:
+            try:
+                actual = function(*a)
+            except ValueError:
+                continue
+            else:
+                raise AssertionError('ValueError not raised in test '
+                            '%s: %s%s' % (id, fn, args_to_str(a)))
+        if 'overflow' in flags:
+            try:
+                actual = function(*a)
+            except OverflowError:
+                continue
+            else:
+                raise AssertionError('OverflowError not raised in test '
+                            '%s: %s%s' % (id, fn, args_to_str(a)))
+        actual = function(*a)
+
+        if 'ignore-real-sign' in flags:
+            actual = (abs(actual[0]), actual[1])
+            expected = (abs(expected[0]), expected[1])
+        if 'ignore-imag-sign' in flags:
+            actual = (actual[0], abs(actual[1]))
+            expected = (expected[0], abs(expected[1]))
+
+        # for the real part of the log function, we allow an
+        # absolute error of up to 2e-15.
+        if fn in ('log', 'log10'):
+            real_abs_err = 2e-15
+        else:
+            real_abs_err = 5e-323
+        error_message = (
+            '%s: %s%s\n'
+            'Expected: complex(%r, %r)\n'
+            'Received: complex(%r, %r)\n'
+            ) % (id, fn, args_to_str(a),
+                 expected[0], expected[1],
+                 actual[0], actual[1])
+
+        rAssertAlmostEqual(expected[0], actual[0],
+                           abs_err=real_abs_err,
+                           msg=error_message)
+        rAssertAlmostEqual(expected[1], actual[1],
+                           abs_err=real_abs_err,
+                           msg=error_message)