[pypy-commit] pypy numpypy-complex2: copy complex_testcases to test_ufuncs
mattip
noreply at buildbot.pypy.org
Fri Aug 31 17:45:19 CEST 2012
Author: mattip <matti.picus at gmail.com>
Branch: numpypy-complex2
Changeset: r57063:9ab2857e5445
Date: 2012-08-31 15:34 +0300
http://bitbucket.org/pypy/pypy/changeset/9ab2857e5445/
Log: copy complex_testcases to test_ufuncs
diff --git a/pypy/rlib/test/rcomplex_testcases.txt b/pypy/module/micronumpy/test/complex_testcases.txt
copy from pypy/rlib/test/rcomplex_testcases.txt
copy to pypy/module/micronumpy/test/complex_testcases.txt
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
@@ -2,6 +2,12 @@
from pypy.module.micronumpy.test.test_base import BaseNumpyAppTest
class AppTestUfuncs(BaseNumpyAppTest):
+ def setup_class(cls):
+ import os
+ BaseNumpyAppTest.setup_class.im_func(cls)
+ fname = os.path.join(os.path.dirname(__file__), 'complex_testcases.txt')
+ cls.w_testcases = cls.space.wrap(fname)
+
def test_ufunc_instance(self):
from _numpypy import add, ufunc
@@ -856,7 +862,8 @@
def test_complex(self):
from _numpypy import (complex128, complex64, add,
- subtract as sub, multiply, divide, negative, abs, fmod)
+ subtract as sub, multiply, divide, negative, abs, fmod,
+ reciprocal)
from _numpypy import (equal, not_equal, greater, greater_equal, less,
less_equal)
@@ -916,7 +923,147 @@
assert repr(abs(inf_c)) == 'inf'
assert repr(abs(n)) == 'nan'
+ assert False, 'untested: copysign, reciprocal, sign, floor_div, ' + \
+ 'signbit, fabs, fmax, fmin, floor, ceil, trunc, ' + \
+ 'exp2, expm1, isnan, isinf, isneginf, isposinf, ' + \
+ 'isfinite, radians, degrees, log2, log10, log1p, ' + \
+ 'logaddexp, npy_log2_1p, logaddexp2'
def test_complex_math(self):
- # from _numpypy import
- pass
+ import _numpypy as np
+ from math import isnan, isinf, copysign
+ from sys import version_info
+ testcases = self.testcases
+ def parse_testfile(fname):
+ """Parse a file with test values
+
+ Empty lines or lines starting with -- are ignored
+ yields id, fn, arg_real, arg_imag, exp_real, exp_imag
+ """
+ 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('->')
+ id, fn, arg_real, arg_imag = lhs.split()
+ rhs_pieces = rhs.split()
+ exp_real, exp_imag = rhs_pieces[0], rhs_pieces[1]
+ flags = rhs_pieces[2:]
+
+ yield (id, fn,
+ float(arg_real), float(arg_imag),
+ float(exp_real), float(exp_imag),
+ flags
+ )
+ def rAssertAlmostEqual(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
+ raise AssertionError(msg + '%r should be nan' % (b,))
+
+ if isinf(a):
+ if a == b:
+ return
+ 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
+ raise AssertionError(msg + '%r and %r are not sufficiently close' % (a, b))
+ tested_funcs=[]
+ for complex_, abs_err in ((np.complex128, 5e-323), (np.complex64, 5e-32)):
+ for id, fn, ar, ai, er, ei, flags in parse_testfile(testcases):
+ arg = complex_(complex(ar, ai))
+ expected = (er, ei)
+ if fn.startswith('acos'):
+ fn = 'arc' + fn[1:]
+ elif fn.startswith('asin'):
+ fn = 'arc' + fn[1:]
+ elif fn.startswith('atan'):
+ fn = 'arc' + fn[1:]
+ function = getattr(np, fn)
+ #
+ #if 'divide-by-zero' in flags or 'invalid' in flags:
+ # try:
+ # _actual = function(arg)
+ # except ValueError:
+ # continue
+ # else:
+ # raise AssertionError('ValueError not raised in test '
+ # '%s: %s(complex(%r, %r))' % (id, fn, ar, ai))
+ #if 'overflow' in flags:
+ # try:
+ # _actual = function(arg)
+ # except OverflowError:
+ # continue
+ # else:
+ # raise AssertionError('OverflowError not raised in test '
+ # '%s: %s(complex(%r, %r))' % (id, fn, ar, ai))
+ _actual = function(arg)
+ actual = (_actual.real, _actual.imag)
+
+ 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 = abs_err
+
+ error_message = (
+ '%s: %s(complex(%r, %r))\n'
+ 'Expected: complex(%r, %r)\n'
+ 'Received: complex(%r, %r)\n'
+ ) % (id, fn, ar, ai,
+ expected[0], expected[1],
+ actual[0], actual[1])
+
+ if not function in tested_funcs:
+ print 'fuction',function
+ tested_funcs.append(function)
+ rAssertAlmostEqual(expected[0], actual[0],
+ abs_err=real_abs_err,
+ msg=error_message)
+ rAssertAlmostEqual(expected[1], 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
@@ -5,8 +5,8 @@
from pypy.interpreter.error import OperationError
from pypy.module.micronumpy import interp_boxes
from pypy.objspace.std.floatobject import float2string
-from pypy.objspace.std.complexobject import W_ComplexObject, str_format
-from pypy.rlib import rfloat, libffi, clibffi, rcomplex
+from pypy.objspace.std.complexobject import str_format
+from pypy.rlib import rfloat, clibffi, rcomplex
from pypy.rlib.rawstorage import (alloc_raw_storage, raw_storage_setitem,
raw_storage_getitem)
from pypy.rlib.objectmodel import specialize, we_are_translated
@@ -15,7 +15,6 @@
from pypy.rlib.rstruct.runpack import runpack
from pypy.tool.sourcetools import func_with_new_name
from pypy.rlib import jit
-from pypy.module import cmath
degToRad = math.pi / 180.0
@@ -39,12 +38,17 @@
specialize.argtype(1)(func)
@functools.wraps(func)
def dispatcher(self, v):
- return self.box_complex(
- *func(
- self,
- self.for_computation(self.unbox(v))
+ try:
+ 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):
@@ -1113,22 +1117,14 @@
except ZeroDivisionError:
return rfloat.NAN, 0
- #complex mod does not exist
+ #complex mod does not exist in numpy
#@simple_binary_op
#def mod(self, v1, v2):
# return math.fmod(v1, v2)
- @simple_binary_op
+ @complex_binary_op
def pow(self, v1, v2):
- try:
- return math.pow(v1, v2)
- except ValueError:
- return rfloat.NAN
- except OverflowError:
- if math.modf(v2)[0] == 0 and math.modf(v2 / 2)[0] != 0:
- # Odd integer powers result in the same sign as the base
- return rfloat.copysign(rfloat.INFINITY, v1)
- return rfloat.INFINITY
+ return rcomplex.c_pow(v1, v2)
@simple_binary_op
def copysign(self, v1, v2):
@@ -1144,9 +1140,9 @@
def signbit(self, v):
return rfloat.copysign(1.0, v) < 0.0
- @simple_unary_op
+ @complex_unary_op
def fabs(self, v):
- return math.fabs(v)
+ return rcomplex.abs(*v)
@simple_binary_op
def fmax(self, v1, v2):
@@ -1164,17 +1160,17 @@
return v2
return min(v1, v2)
- @simple_binary_op
- def fmod(self, v1, v2):
- try:
- return math.fmod(v1, v2)
- except ValueError:
- return rfloat.NAN
+ #@simple_binary_op
+ #def fmod(self, v1, v2):
+ # try:
+ # return math.fmod(v1, v2)
+ # except ValueError:
+ # return rfloat.NAN
@simple_unary_op
def reciprocal(self, v):
- if v == 0.0:
- return rfloat.copysign(rfloat.INFINITY, v)
+ if abs(v) == 0.0:
+ return self.copysign(rfloat.INFINITY, v)
return 1.0 / v
@simple_unary_op
@@ -1213,74 +1209,70 @@
except OverflowError:
return rfloat.INFINITY
- @simple_unary_op
+ @complex_unary_op
def sin(self, v):
- return math.sin(v)
+ return rcomplex.c_sin(*v)
- @simple_unary_op
+ @complex_unary_op
def cos(self, v):
- return math.cos(v)
+ return rcomplex.c_cos(*v)
- @simple_unary_op
+ @complex_unary_op
def tan(self, v):
- return math.tan(v)
+ return rcomplex.c_tan(*v)
- @simple_unary_op
+ @complex_unary_op
def arcsin(self, v):
- if not -1.0 <= v <= 1.0:
- return rfloat.NAN
- return math.asin(v)
+ return rcomplex.c_asin(*v)
- @simple_unary_op
+ @complex_unary_op
def arccos(self, v):
- if not -1.0 <= v <= 1.0:
- return rfloat.NAN
- return math.acos(v)
+ return rcomplex.c_acos(*v)
- @simple_unary_op
+ @complex_unary_op
def arctan(self, v):
- return math.atan(v)
+ if v[0]==0 and (v[1]==1 or v[1] == -1):
+ #This is the place to print a "runtime warning"
+ return rfloat.NAN, math.copysign(rfloat.INFINITY, v[1])
+ return rcomplex.c_atan(*v)
- @simple_binary_op
+ @complex_binary_op
def arctan2(self, v1, v2):
- return math.atan2(v1, v2)
+ return rcomplex.c_atan2(v1, v2)
- @simple_unary_op
+ @complex_unary_op
def sinh(self, v):
- return math.sinh(v)
+ return rcomplex.c_sinh(*v)
- @simple_unary_op
+ @complex_unary_op
def cosh(self, v):
- return math.cosh(v)
+ return rcomplex.c_cosh(*v)
- @simple_unary_op
+ @complex_unary_op
def tanh(self, v):
- return math.tanh(v)
+ return rcomplex.c_tanh(*v)
- @simple_unary_op
+ @complex_unary_op
def arcsinh(self, v):
- return math.asinh(v)
+ return rcomplex.c_asinh(*v)
- @simple_unary_op
+ @complex_unary_op
def arccosh(self, v):
- if v < 1.0:
- return rfloat.NAN
- return math.acosh(v)
+ return rcomplex.c_acosh(*v)
- @simple_unary_op
+ @complex_unary_op
def arctanh(self, v):
- if v == 1.0 or v == -1.0:
- return math.copysign(rfloat.INFINITY, v)
+ if v[1] == 0 and (v[0] == 1.0 or v[0] == -1.0):
+ return math.copysign(rfloat.INFINITY, v[0]), 0.
if not -1.0 < v < 1.0:
- return rfloat.NAN
- return math.atanh(v)
+ return rfloat.NAN, 0.
+ return rcomplex.c_atanh(*v)
+
+
- @simple_unary_op
+ @complex_unary_op
def sqrt(self, v):
- try:
- return math.sqrt(v)
- except ValueError:
- return rfloat.NAN
+ return rcomplex.c_sqrt(*v)
@simple_unary_op
def square(self, v):
@@ -1315,27 +1307,13 @@
def degrees(self, v):
return v / degToRad
- @simple_unary_op
+ @complex_unary_op
def log(self, v):
- try:
- return math.log(v)
- except ValueError:
- if v == 0.0:
- # CPython raises ValueError here, so we have to check
- # the value to find the correct numpy return value
- return -rfloat.INFINITY
- return rfloat.NAN
+ return rcomplex.c_log(v)
@simple_unary_op
def log2(self, v):
- try:
- return math.log(v) / log2
- except ValueError:
- if v == 0.0:
- # CPython raises ValueError here, so we have to check
- # the value to find the correct numpy return value
- return -rfloat.INFINITY
- return rfloat.NAN
+ return self.log(v) / log2
@simple_unary_op
def log10(self, v):
More information about the pypy-commit
mailing list