Commit 603ae9e3 authored by Mark Dickinson's avatar Mark Dickinson

Issue #7554: Various fixups in test_cmath.py: remove code duplication,

use new-style formatting.  Thanks Florent Xicluna for the patch.
parent ed284991
...@@ -46,37 +46,6 @@ complex_nans = [complex(x, y) for x, y in [ ...@@ -46,37 +46,6 @@ complex_nans = [complex(x, y) for x, y in [
(INF, NAN) (INF, NAN)
]] ]]
def almostEqualF(a, b, rel_err=2e-15, abs_err = 5e-323):
"""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 math.isnan(a):
return math.isnan(b)
if math.isinf(a):
return 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:
return math.copysign(1., a) == math.copysign(1., 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:
return False
else:
return absolute_error <= max(abs_err, rel_err * abs(a))
class CMathTests(unittest.TestCase): class CMathTests(unittest.TestCase):
# list of all functions in cmath # list of all functions in cmath
test_functions = [getattr(cmath, fname) for fname in [ test_functions = [getattr(cmath, fname) for fname in [
...@@ -93,47 +62,63 @@ class CMathTests(unittest.TestCase): ...@@ -93,47 +62,63 @@ class CMathTests(unittest.TestCase):
def tearDown(self): def tearDown(self):
self.test_values.close() self.test_values.close()
def rAssertAlmostEqual(self, a, b, rel_err = 2e-15, abs_err = 5e-323): def rAssertAlmostEqual(self, a, b, rel_err = 2e-15, abs_err = 5e-323,
"""Check that two floating-point numbers are almost equal.""" msg=None):
"""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 # special values testing
if math.isnan(a): if math.isnan(a):
if math.isnan(b): if math.isnan(b):
return return
self.fail("%s should be nan" % repr(b)) self.fail(msg or '{!r} should be nan'.format(b))
if math.isinf(a): if math.isinf(a):
if a == b: if a == b:
return return
self.fail("finite result where infinity excpected: " self.fail(msg or 'finite result where infinity expected: '
"expected %s, got %s" % (repr(a), repr(b))) 'expected {!r}, got {!r}'.format(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: if not a and not b:
if math.atan2(a, -1.) != math.atan2(b, -1.): if math.copysign(1., a) != math.copysign(1., b):
self.fail("zero has wrong sign: expected %s, got %s" % self.fail(msg or 'zero has wrong sign: expected {!r}, '
(repr(a), repr(b))) 'got {!r}'.format(a, b))
# test passes if either the absolute error or the relative # if a-b overflows, or b is infinite, return False. Again, in
# error is sufficiently small. The defaults amount to an # theory there are examples where a is within a few ulps of the
# error of between 9 ulps and 19 ulps on an IEEE-754 compliant # max representable float, and then b could legitimately be
# machine. # infinite. In practice these examples are rare.
try: try:
absolute_error = abs(b-a) absolute_error = abs(b-a)
except OverflowError: except OverflowError:
pass pass
else: 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)): if absolute_error <= max(abs_err, rel_err * abs(a)):
return return
self.fail("%s and %s are not sufficiently close" % (repr(a), repr(b))) self.fail(msg or
'{!r} and {!r} are not sufficiently close'.format(a, b))
def test_constants(self): def test_constants(self):
e_expected = 2.71828182845904523536 e_expected = 2.71828182845904523536
pi_expected = 3.14159265358979323846 pi_expected = 3.14159265358979323846
self.assertAlmostEqual(cmath.pi, pi_expected, places=9, self.assertAlmostEqual(cmath.pi, pi_expected, places=9,
msg="cmath.pi is %s; should be %s" % (cmath.pi, pi_expected)) msg="cmath.pi is {}; should be {}".format(cmath.pi, pi_expected))
self.assertAlmostEqual(cmath.e, e_expected, places=9, self.assertAlmostEqual(cmath.e, e_expected, places=9,
msg="cmath.e is %s; should be %s" % (cmath.e, e_expected)) msg="cmath.e is {}; should be {}".format(cmath.e, e_expected))
def test_user_object(self): def test_user_object(self):
# Test automatic calling of __complex__ and __float__ by cmath # Test automatic calling of __complex__ and __float__ by cmath
...@@ -325,8 +310,8 @@ class CMathTests(unittest.TestCase): ...@@ -325,8 +310,8 @@ class CMathTests(unittest.TestCase):
except ValueError: except ValueError:
continue continue
else: else:
test_str = "%s: %s(complex(%r, %r))" % (id, fn, ar, ai) self.fail('ValueError not raised in test '
self.fail('ValueError not raised in test %s' % test_str) '{}: {}(complex({!r}, {!r}))'.format(id, fn, ar, ai))
if 'overflow' in flags: if 'overflow' in flags:
try: try:
...@@ -334,8 +319,8 @@ class CMathTests(unittest.TestCase): ...@@ -334,8 +319,8 @@ class CMathTests(unittest.TestCase):
except OverflowError: except OverflowError:
continue continue
else: else:
test_str = "%s: %s(complex(%r, %r))" % (id, fn, ar, ai) self.fail('OverflowError not raised in test '
self.fail('OverflowError not raised in test %s' % test_str) '{}: {}(complex({!r}, {!r}))'.format(id, fn, ar, ai))
actual = function(arg) actual = function(arg)
...@@ -353,17 +338,19 @@ class CMathTests(unittest.TestCase): ...@@ -353,17 +338,19 @@ class CMathTests(unittest.TestCase):
else: else:
real_abs_err = 5e-323 real_abs_err = 5e-323
if not (almostEqualF(expected.real, actual.real, error_message = (
abs_err = real_abs_err) and '{}: {}(complex({!r}, {!r}))\n'
almostEqualF(expected.imag, actual.imag)): 'Expected: complex({!r}, {!r})\n'
error_message = ( 'Received: complex({!r}, {!r})\n'
"%s: %s(complex(%r, %r))\n" % (id, fn, ar, ai) + 'Received value insufficiently close to expected value.'
"Expected: complex(%r, %r)\n" % ).format(id, fn, ar, ai,
(expected.real, expected.imag) + expected.real, expected.imag,
"Received: complex(%r, %r)\n" % actual.real, actual.imag)
(actual.real, actual.imag) + self.rAssertAlmostEqual(expected.real, actual.real,
"Received value insufficiently close to expected value.") abs_err=real_abs_err,
self.fail(error_message) msg=error_message)
self.rAssertAlmostEqual(expected.imag, actual.imag,
msg=error_message)
def assertCISEqual(self, a, b): def assertCISEqual(self, a, b):
eps = 1E-7 eps = 1E-7
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment