+from math import copysign, isnan
+
+
class ExceptionIsLikeMixin:
def assertExceptionIsLike(self, exc, template):
"""
self.assertEqual(len(exc.exceptions), len(template.exceptions))
for e, t in zip(exc.exceptions, template.exceptions):
self.assertExceptionIsLike(e, t)
+
+
+class FloatsAreIdenticalMixin:
+ def assertFloatsAreIdentical(self, x, y):
+ """Fail unless floats x and y are identical, in the sense that:
+ (1) both x and y are nans, or
+ (2) both x and y are infinities, with the same sign, or
+ (3) both x and y are zeros, with the same sign, or
+ (4) x and y are both finite and nonzero, and x == y
+
+ """
+ msg = 'floats {!r} and {!r} are not identical'
+
+ if isnan(x) or isnan(y):
+ if isnan(x) and isnan(y):
+ return
+ elif x == y:
+ if x != 0.0:
+ return
+ # both zero; check that signs match
+ elif copysign(1.0, x) == copysign(1.0, y):
+ return
+ else:
+ msg += ': zeros have different signs'
+ self.fail(msg.format(x, y))
+
+
+class ComplexesAreIdenticalMixin(FloatsAreIdenticalMixin):
+ def assertComplexesAreIdentical(self, x, y):
+ """Fail unless complex numbers x and y have equal values and signs.
+
+ In particular, if x and y both have real (or imaginary) part
+ zero, but the zeros have different signs, this test will fail.
+
+ """
+ self.assertFloatsAreIdentical(x.real, y.real)
+ self.assertFloatsAreIdentical(x.imag, y.imag)
from test.support import import_helper
from test.support import script_helper
from test.support import warnings_helper
+from test.support.testcase import FloatsAreIdenticalMixin
# Skip this test if the _testcapi module isn't available.
_testcapi = import_helper.import_module('_testcapi')
from _testcapi import getargs_keywords, getargs_keyword_only
self.assertEqual(VERY_LARGE & ULLONG_MAX, getargs_K(VERY_LARGE))
-class Float_TestCase(unittest.TestCase):
- def assertEqualWithSign(self, actual, expected):
- self.assertEqual(actual, expected)
- self.assertEqual(math.copysign(1, actual), math.copysign(1, expected))
-
+class Float_TestCase(unittest.TestCase, FloatsAreIdenticalMixin):
def test_f(self):
from _testcapi import getargs_f
self.assertEqual(getargs_f(4.25), 4.25)
self.assertEqual(getargs_f(DBL_MAX), INF)
self.assertEqual(getargs_f(-DBL_MAX), -INF)
if FLT_MIN > DBL_MIN:
- self.assertEqualWithSign(getargs_f(DBL_MIN), 0.0)
- self.assertEqualWithSign(getargs_f(-DBL_MIN), -0.0)
- self.assertEqualWithSign(getargs_f(0.0), 0.0)
- self.assertEqualWithSign(getargs_f(-0.0), -0.0)
+ self.assertFloatsAreIdentical(getargs_f(DBL_MIN), 0.0)
+ self.assertFloatsAreIdentical(getargs_f(-DBL_MIN), -0.0)
+ self.assertFloatsAreIdentical(getargs_f(0.0), 0.0)
+ self.assertFloatsAreIdentical(getargs_f(-0.0), -0.0)
r = getargs_f(NAN)
self.assertNotEqual(r, r)
self.assertEqual(getargs_d(x), x)
self.assertRaises(OverflowError, getargs_d, 1<<DBL_MAX_EXP)
self.assertRaises(OverflowError, getargs_d, -1<<DBL_MAX_EXP)
- self.assertEqualWithSign(getargs_d(0.0), 0.0)
- self.assertEqualWithSign(getargs_d(-0.0), -0.0)
+ self.assertFloatsAreIdentical(getargs_d(0.0), 0.0)
+ self.assertFloatsAreIdentical(getargs_d(-0.0), -0.0)
r = getargs_d(NAN)
self.assertNotEqual(r, r)
self.assertEqual(getargs_D(c), c)
c = complex(1.0, x)
self.assertEqual(getargs_D(c), c)
- self.assertEqualWithSign(getargs_D(complex(0.0, 1.0)).real, 0.0)
- self.assertEqualWithSign(getargs_D(complex(-0.0, 1.0)).real, -0.0)
- self.assertEqualWithSign(getargs_D(complex(1.0, 0.0)).imag, 0.0)
- self.assertEqualWithSign(getargs_D(complex(1.0, -0.0)).imag, -0.0)
+ self.assertFloatsAreIdentical(getargs_D(complex(0.0, 1.0)).real, 0.0)
+ self.assertFloatsAreIdentical(getargs_D(complex(-0.0, 1.0)).real, -0.0)
+ self.assertFloatsAreIdentical(getargs_D(complex(1.0, 0.0)).imag, 0.0)
+ self.assertFloatsAreIdentical(getargs_D(complex(1.0, -0.0)).imag, -0.0)
class Paradox:
from test.support import requires_IEEE_754, cpython_only, import_helper
+from test.support.testcase import ComplexesAreIdenticalMixin
from test.test_math import parse_testfile, test_file
import test.test_math as test_math
import unittest
(INF, NAN)
]]
-class CMathTests(unittest.TestCase):
+class CMathTests(ComplexesAreIdenticalMixin, unittest.TestCase):
# list of all functions in cmath
test_functions = [getattr(cmath, fname) for fname in [
'acos', 'acosh', 'asin', 'asinh', 'atan', 'atanh',
def tearDown(self):
self.test_values.close()
- def assertFloatIdentical(self, x, y):
- """Fail unless floats x and y are identical, in the sense that:
- (1) both x and y are nans, or
- (2) both x and y are infinities, with the same sign, or
- (3) both x and y are zeros, with the same sign, or
- (4) x and y are both finite and nonzero, and x == y
-
- """
- msg = 'floats {!r} and {!r} are not identical'
-
- if math.isnan(x) or math.isnan(y):
- if math.isnan(x) and math.isnan(y):
- return
- elif x == y:
- if x != 0.0:
- return
- # both zero; check that signs match
- elif math.copysign(1.0, x) == math.copysign(1.0, y):
- return
- else:
- msg += ': zeros have different signs'
- self.fail(msg.format(x, y))
-
- def assertComplexIdentical(self, x, y):
- """Fail unless complex numbers x and y have equal values and signs.
-
- In particular, if x and y both have real (or imaginary) part
- zero, but the zeros have different signs, this test will fail.
-
- """
- self.assertFloatIdentical(x.real, y.real)
- self.assertFloatIdentical(x.imag, y.imag)
-
def rAssertAlmostEqual(self, a, b, rel_err = 2e-15, abs_err = 5e-323,
msg=None):
"""Fail if the two floating-point numbers are not almost equal.
@requires_IEEE_754
def testTanhSign(self):
for z in complex_zeros:
- self.assertComplexIdentical(cmath.tanh(z), z)
+ self.assertComplexesAreIdentical(cmath.tanh(z), z)
# The algorithm used for atan and atanh makes use of the system
# log1p function; If that system function doesn't respect the sign
@requires_IEEE_754
def testAtanSign(self):
for z in complex_zeros:
- self.assertComplexIdentical(cmath.atan(z), z)
+ self.assertComplexesAreIdentical(cmath.atan(z), z)
@requires_IEEE_754
def testAtanhSign(self):
for z in complex_zeros:
- self.assertComplexIdentical(cmath.atanh(z), z)
+ self.assertComplexesAreIdentical(cmath.atanh(z), z)
class IsCloseTests(test_math.IsCloseTests):
import unittest
import sys
from test import support
+from test.support.testcase import ComplexesAreIdenticalMixin
from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
INVALID_UNDERSCORE_LITERALS)
def __complex__(self):
return self.value
-class ComplexTest(unittest.TestCase):
+class ComplexTest(ComplexesAreIdenticalMixin, unittest.TestCase):
def assertAlmostEqual(self, a, b):
if isinstance(a, complex):
# check that relative difference < eps
self.assertTrue(abs((x-y)/y) < eps)
- def assertFloatsAreIdentical(self, x, y):
- """assert that floats x and y are identical, in the sense that:
- (1) both x and y are nans, or
- (2) both x and y are infinities, with the same sign, or
- (3) both x and y are zeros, with the same sign, or
- (4) x and y are both finite and nonzero, and x == y
-
- """
- msg = 'floats {!r} and {!r} are not identical'
-
- if isnan(x) or isnan(y):
- if isnan(x) and isnan(y):
- return
- elif x == y:
- if x != 0.0:
- return
- # both zero; check that signs match
- elif copysign(1.0, x) == copysign(1.0, y):
- return
- else:
- msg += ': zeros have different signs'
- self.fail(msg.format(x, y))
-
def assertClose(self, x, y, eps=1e-9):
"""Return true iff complexes x and y "are close"."""
self.assertCloseAbs(x.real, y.real, eps)
for y in vals:
z = complex(x, y)
roundtrip = complex(repr(z))
- self.assertFloatsAreIdentical(z.real, roundtrip.real)
- self.assertFloatsAreIdentical(z.imag, roundtrip.imag)
+ self.assertComplexesAreIdentical(z, roundtrip)
# if we predefine some constants, then eval(repr(z)) should
# also work, except that it might change the sign of zeros
import unittest
from test import support
+from test.support.testcase import FloatsAreIdenticalMixin
from test.test_grammar import (VALID_UNDERSCORE_LITERALS,
INVALID_UNDERSCORE_LITERALS)
from math import isinf, isnan, copysign, ldexp
fromHex = float.fromhex
toHex = float.hex
-class HexFloatTestCase(unittest.TestCase):
+class HexFloatTestCase(FloatsAreIdenticalMixin, unittest.TestCase):
MAX = fromHex('0x.fffffffffffff8p+1024') # max normal
MIN = fromHex('0x1p-1022') # min normal
TINY = fromHex('0x0.0000000000001p-1022') # min subnormal
EPS = fromHex('0x0.0000000000001p0') # diff between 1.0 and next float up
def identical(self, x, y):
- # check that floats x and y are identical, or that both
- # are NaNs
- if isnan(x) or isnan(y):
- if isnan(x) == isnan(y):
- return
- elif x == y and (x != 0.0 or copysign(1.0, x) == copysign(1.0, y)):
- return
- self.fail('%r not identical to %r' % (x, y))
+ self.assertFloatsAreIdentical(x, y)
def test_ends(self):
self.identical(self.MIN, ldexp(1.0, -1022))