cpython/Lib/test/test_math.py
Georg Brandl f78e02b798 Merged revisions 63562,63570,63728,63734,63784,63788,63802,63817,63827,63839,63887,63975,63998 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r63562 | martin.v.loewis | 2008-05-23 17:06:50 +0200 (Fri, 23 May 2008) | 2 lines

  Patch #1722225: Support QNX 6.
........
  r63570 | trent.nelson | 2008-05-23 22:33:14 +0200 (Fri, 23 May 2008) | 1 line

  Introduce a user macro named $(externalsDir), which should point to the root directory of where all the external sources should live.  Developers can change this value if their external sources live elsewhere.  The default of '..\..' matches the current status quo.
........
  r63728 | gregory.p.smith | 2008-05-26 23:16:34 +0200 (Mon, 26 May 2008) | 4 lines

  Fix issue2589: there was a potential integer overflow leading to
  memory corruption on esoteric platforms and incorrect behavior on
  normal platforms.
........
  r63734 | gregory.p.smith | 2008-05-27 00:07:28 +0200 (Tue, 27 May 2008) | 3 lines

  Fix issue2588: Do not execute str[size-1] = '\0' when a 0 size is
  passed in.  (The assert won't prevent this in non-debug builds).
........
  r63784 | raymond.hettinger | 2008-05-29 10:38:23 +0200 (Thu, 29 May 2008) | 1 line

  Fix two typos.
........
  r63788 | facundo.batista | 2008-05-29 18:39:26 +0200 (Thu, 29 May 2008) | 6 lines


  Fixed the semantic of timeout for socket.create_connection and
  all the upper level libraries that use it, including urllib2.
  Added and fixed some tests, and changed docs correspondingly.
  Thanks to John J Lee for the patch and the pusing, :)
........
  r63802 | mark.dickinson | 2008-05-30 04:46:53 +0200 (Fri, 30 May 2008) | 2 lines

  Fix typo in testSum
........
  r63817 | raymond.hettinger | 2008-05-30 20:20:50 +0200 (Fri, 30 May 2008) | 8 lines

  * Mark intermedidate computes values (hi, lo, yr) as volatile.
  * Expand comments.
  * Swap variable names in the sum_exact code so that x and y
    are consistently chosen as the larger and smaller magnitude
    values respectively.
........
  r63827 | raymond.hettinger | 2008-05-31 05:24:31 +0200 (Sat, 31 May 2008) | 1 line

  Implement heapq in terms of less-than (to match list.sort()).
........
  r63839 | gerhard.haering | 2008-05-31 23:33:27 +0200 (Sat, 31 May 2008) | 2 lines

  Fixed rowcount for SELECT statements. They're -1 now (again), for better DB-API 2.0 compliance.
........
  r63887 | gregory.p.smith | 2008-06-02 06:05:52 +0200 (Mon, 02 Jun 2008) | 4 lines

  Fix issue 2782: be less strict about the format string type in strftime.
  Accept unicode and anything else ParseTuple "s#" can deal with.  This
  matches the time.strftime behavior.
........
  r63975 | neal.norwitz | 2008-06-06 06:47:01 +0200 (Fri, 06 Jun 2008) | 3 lines

  Aldo Cortesi confirmed this is still needed for OpenBSD 4.2 and 4.3.
  (I didn't regen configure, since I don't have a working autoconf.)
........
  r63998 | raymond.hettinger | 2008-06-06 23:47:51 +0200 (Fri, 06 Jun 2008) | 1 line

  Issue 3501: Make heapq support both __le__ and __lt__.
........
2008-06-10 17:40:04 +00:00

932 lines
40 KiB
Python

# Python test set -- math module
# XXXX Should not do tests around zero only
from test.support import run_unittest, verbose
import unittest
import math
import os
import sys
eps = 1E-05
NAN = float('nan')
INF = float('inf')
NINF = float('-inf')
# locate file with test values
if __name__ == '__main__':
file = sys.argv[0]
else:
file = __file__
test_dir = os.path.dirname(file) or os.curdir
test_file = os.path.join(test_dir, 'cmath_testcases.txt')
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
)
class MathTests(unittest.TestCase):
def ftest(self, name, value, expected):
if abs(value-expected) > eps:
# Use %r instead of %f so the error message
# displays full precision. Otherwise discrepancies
# in the last few bits will lead to very confusing
# error messages
self.fail('%s returned %r, expected %r' %
(name, value, expected))
def testConstants(self):
self.ftest('pi', math.pi, 3.1415926)
self.ftest('e', math.e, 2.7182818)
def testAcos(self):
self.assertRaises(TypeError, math.acos)
self.ftest('acos(-1)', math.acos(-1), math.pi)
self.ftest('acos(0)', math.acos(0), math.pi/2)
self.ftest('acos(1)', math.acos(1), 0)
self.assertRaises(ValueError, math.acos, INF)
self.assertRaises(ValueError, math.acos, NINF)
self.assert_(math.isnan(math.acos(NAN)))
def testAcosh(self):
self.assertRaises(TypeError, math.acosh)
self.ftest('acosh(1)', math.acosh(1), 0)
self.ftest('acosh(2)', math.acosh(2), 1.3169578969248168)
self.assertRaises(ValueError, math.acosh, 0)
self.assertRaises(ValueError, math.acosh, -1)
self.assertEquals(math.acosh(INF), INF)
self.assertRaises(ValueError, math.acosh, NINF)
self.assert_(math.isnan(math.acosh(NAN)))
def testAsin(self):
self.assertRaises(TypeError, math.asin)
self.ftest('asin(-1)', math.asin(-1), -math.pi/2)
self.ftest('asin(0)', math.asin(0), 0)
self.ftest('asin(1)', math.asin(1), math.pi/2)
self.assertRaises(ValueError, math.asin, INF)
self.assertRaises(ValueError, math.asin, NINF)
self.assert_(math.isnan(math.asin(NAN)))
def testAsinh(self):
self.assertRaises(TypeError, math.asinh)
self.ftest('asinh(0)', math.asinh(0), 0)
self.ftest('asinh(1)', math.asinh(1), 0.88137358701954305)
self.ftest('asinh(-1)', math.asinh(-1), -0.88137358701954305)
self.assertEquals(math.asinh(INF), INF)
self.assertEquals(math.asinh(NINF), NINF)
self.assert_(math.isnan(math.asinh(NAN)))
def testAtan(self):
self.assertRaises(TypeError, math.atan)
self.ftest('atan(-1)', math.atan(-1), -math.pi/4)
self.ftest('atan(0)', math.atan(0), 0)
self.ftest('atan(1)', math.atan(1), math.pi/4)
self.ftest('atan(inf)', math.atan(INF), math.pi/2)
self.ftest('atan(-inf)', math.atan(NINF), -math.pi/2)
self.assert_(math.isnan(math.atan(NAN)))
def testAtanh(self):
self.assertRaises(TypeError, math.atan)
self.ftest('atanh(0)', math.atanh(0), 0)
self.ftest('atanh(0.5)', math.atanh(0.5), 0.54930614433405489)
self.ftest('atanh(-0.5)', math.atanh(-0.5), -0.54930614433405489)
self.assertRaises(ValueError, math.atanh, 1)
self.assertRaises(ValueError, math.atanh, -1)
self.assertRaises(ValueError, math.atanh, INF)
self.assertRaises(ValueError, math.atanh, NINF)
self.assert_(math.isnan(math.atanh(NAN)))
def testAtan2(self):
self.assertRaises(TypeError, math.atan2)
self.ftest('atan2(-1, 0)', math.atan2(-1, 0), -math.pi/2)
self.ftest('atan2(-1, 1)', math.atan2(-1, 1), -math.pi/4)
self.ftest('atan2(0, 1)', math.atan2(0, 1), 0)
self.ftest('atan2(1, 1)', math.atan2(1, 1), math.pi/4)
self.ftest('atan2(1, 0)', math.atan2(1, 0), math.pi/2)
# math.atan2(0, x)
self.ftest('atan2(0., -inf)', math.atan2(0., NINF), math.pi)
self.ftest('atan2(0., -2.3)', math.atan2(0., -2.3), math.pi)
self.ftest('atan2(0., -0.)', math.atan2(0., -0.), math.pi)
self.assertEqual(math.atan2(0., 0.), 0.)
self.assertEqual(math.atan2(0., 2.3), 0.)
self.assertEqual(math.atan2(0., INF), 0.)
self.assert_(math.isnan(math.atan2(0., NAN)))
# math.atan2(-0, x)
self.ftest('atan2(-0., -inf)', math.atan2(-0., NINF), -math.pi)
self.ftest('atan2(-0., -2.3)', math.atan2(-0., -2.3), -math.pi)
self.ftest('atan2(-0., -0.)', math.atan2(-0., -0.), -math.pi)
self.assertEqual(math.atan2(-0., 0.), -0.)
self.assertEqual(math.atan2(-0., 2.3), -0.)
self.assertEqual(math.atan2(-0., INF), -0.)
self.assert_(math.isnan(math.atan2(-0., NAN)))
# math.atan2(INF, x)
self.ftest('atan2(inf, -inf)', math.atan2(INF, NINF), math.pi*3/4)
self.ftest('atan2(inf, -2.3)', math.atan2(INF, -2.3), math.pi/2)
self.ftest('atan2(inf, -0.)', math.atan2(INF, -0.0), math.pi/2)
self.ftest('atan2(inf, 0.)', math.atan2(INF, 0.0), math.pi/2)
self.ftest('atan2(inf, 2.3)', math.atan2(INF, 2.3), math.pi/2)
self.ftest('atan2(inf, inf)', math.atan2(INF, INF), math.pi/4)
self.assert_(math.isnan(math.atan2(INF, NAN)))
# math.atan2(NINF, x)
self.ftest('atan2(-inf, -inf)', math.atan2(NINF, NINF), -math.pi*3/4)
self.ftest('atan2(-inf, -2.3)', math.atan2(NINF, -2.3), -math.pi/2)
self.ftest('atan2(-inf, -0.)', math.atan2(NINF, -0.0), -math.pi/2)
self.ftest('atan2(-inf, 0.)', math.atan2(NINF, 0.0), -math.pi/2)
self.ftest('atan2(-inf, 2.3)', math.atan2(NINF, 2.3), -math.pi/2)
self.ftest('atan2(-inf, inf)', math.atan2(NINF, INF), -math.pi/4)
self.assert_(math.isnan(math.atan2(NINF, NAN)))
# math.atan2(+finite, x)
self.ftest('atan2(2.3, -inf)', math.atan2(2.3, NINF), math.pi)
self.ftest('atan2(2.3, -0.)', math.atan2(2.3, -0.), math.pi/2)
self.ftest('atan2(2.3, 0.)', math.atan2(2.3, 0.), math.pi/2)
self.assertEqual(math.atan2(2.3, INF), 0.)
self.assert_(math.isnan(math.atan2(2.3, NAN)))
# math.atan2(-finite, x)
self.ftest('atan2(-2.3, -inf)', math.atan2(-2.3, NINF), -math.pi)
self.ftest('atan2(-2.3, -0.)', math.atan2(-2.3, -0.), -math.pi/2)
self.ftest('atan2(-2.3, 0.)', math.atan2(-2.3, 0.), -math.pi/2)
self.assertEqual(math.atan2(-2.3, INF), -0.)
self.assert_(math.isnan(math.atan2(-2.3, NAN)))
# math.atan2(NAN, x)
self.assert_(math.isnan(math.atan2(NAN, NINF)))
self.assert_(math.isnan(math.atan2(NAN, -2.3)))
self.assert_(math.isnan(math.atan2(NAN, -0.)))
self.assert_(math.isnan(math.atan2(NAN, 0.)))
self.assert_(math.isnan(math.atan2(NAN, 2.3)))
self.assert_(math.isnan(math.atan2(NAN, INF)))
self.assert_(math.isnan(math.atan2(NAN, NAN)))
def testCeil(self):
self.assertRaises(TypeError, math.ceil)
self.assertEquals(int, type(math.ceil(0.5)))
self.ftest('ceil(0.5)', math.ceil(0.5), 1)
self.ftest('ceil(1.0)', math.ceil(1.0), 1)
self.ftest('ceil(1.5)', math.ceil(1.5), 2)
self.ftest('ceil(-0.5)', math.ceil(-0.5), 0)
self.ftest('ceil(-1.0)', math.ceil(-1.0), -1)
self.ftest('ceil(-1.5)', math.ceil(-1.5), -1)
#self.assertEquals(math.ceil(INF), INF)
#self.assertEquals(math.ceil(NINF), NINF)
#self.assert_(math.isnan(math.ceil(NAN)))
class TestCeil:
def __ceil__(self):
return 42
class TestNoCeil:
pass
self.ftest('ceil(TestCeil())', math.ceil(TestCeil()), 42)
self.assertRaises(TypeError, math.ceil, TestNoCeil())
t = TestNoCeil()
t.__ceil__ = lambda *args: args
self.assertRaises(TypeError, math.ceil, t)
self.assertRaises(TypeError, math.ceil, t, 0)
if float.__getformat__("double").startswith("IEEE"):
def testCopysign(self):
self.assertRaises(TypeError, math.copysign)
# copysign should let us distinguish signs of zeros
self.assertEquals(copysign(1., 0.), 1.)
self.assertEquals(copysign(1., -0.), -1.)
self.assertEquals(copysign(INF, 0.), INF)
self.assertEquals(copysign(INF, -0.), NINF)
self.assertEquals(copysign(NINF, 0.), INF)
self.assertEquals(copysign(NINF, -0.), NINF)
# and of infinities
self.assertEquals(copysign(1., INF), 1.)
self.assertEquals(copysign(1., NINF), -1.)
self.assertEquals(copysign(INF, INF), INF)
self.assertEquals(copysign(INF, NINF), NINF)
self.assertEquals(copysign(NINF, INF), INF)
self.assertEquals(copysign(NINF, NINF), NINF)
self.assert_(math.isnan(copysign(NAN, 1.)))
self.assert_(math.isnan(copysign(NAN, INF)))
self.assert_(math.isnan(copysign(NAN, NINF)))
self.assert_(math.isnan(copysign(NAN, NAN)))
# copysign(INF, NAN) may be INF or it may be NINF, since
# we don't know whether the sign bit of NAN is set on any
# given platform.
self.assert_(math.isinf(copysign(INF, NAN)))
# similarly, copysign(2., NAN) could be 2. or -2.
self.assertEquals(abs(copysign(2., NAN)), 2.)
def testCos(self):
self.assertRaises(TypeError, math.cos)
self.ftest('cos(-pi/2)', math.cos(-math.pi/2), 0)
self.ftest('cos(0)', math.cos(0), 1)
self.ftest('cos(pi/2)', math.cos(math.pi/2), 0)
self.ftest('cos(pi)', math.cos(math.pi), -1)
try:
self.assert_(math.isnan(math.cos(INF)))
self.assert_(math.isnan(math.cos(NINF)))
except ValueError:
self.assertRaises(ValueError, math.cos, INF)
self.assertRaises(ValueError, math.cos, NINF)
self.assert_(math.isnan(math.cos(NAN)))
def testCosh(self):
self.assertRaises(TypeError, math.cosh)
self.ftest('cosh(0)', math.cosh(0), 1)
self.ftest('cosh(2)-2*cosh(1)**2', math.cosh(2)-2*math.cosh(1)**2, -1) # Thanks to Lambert
self.assertEquals(math.cosh(INF), INF)
self.assertEquals(math.cosh(NINF), INF)
self.assert_(math.isnan(math.cosh(NAN)))
def testDegrees(self):
self.assertRaises(TypeError, math.degrees)
self.ftest('degrees(pi)', math.degrees(math.pi), 180.0)
self.ftest('degrees(pi/2)', math.degrees(math.pi/2), 90.0)
self.ftest('degrees(-pi/4)', math.degrees(-math.pi/4), -45.0)
def testExp(self):
self.assertRaises(TypeError, math.exp)
self.ftest('exp(-1)', math.exp(-1), 1/math.e)
self.ftest('exp(0)', math.exp(0), 1)
self.ftest('exp(1)', math.exp(1), math.e)
self.assertEquals(math.exp(INF), INF)
self.assertEquals(math.exp(NINF), 0.)
self.assert_(math.isnan(math.exp(NAN)))
def testFabs(self):
self.assertRaises(TypeError, math.fabs)
self.ftest('fabs(-1)', math.fabs(-1), 1)
self.ftest('fabs(0)', math.fabs(0), 0)
self.ftest('fabs(1)', math.fabs(1), 1)
def testFloor(self):
self.assertRaises(TypeError, math.floor)
self.assertEquals(int, type(math.floor(0.5)))
self.ftest('floor(0.5)', math.floor(0.5), 0)
self.ftest('floor(1.0)', math.floor(1.0), 1)
self.ftest('floor(1.5)', math.floor(1.5), 1)
self.ftest('floor(-0.5)', math.floor(-0.5), -1)
self.ftest('floor(-1.0)', math.floor(-1.0), -1)
self.ftest('floor(-1.5)', math.floor(-1.5), -2)
# pow() relies on floor() to check for integers
# This fails on some platforms - so check it here
self.ftest('floor(1.23e167)', math.floor(1.23e167), 1.23e167)
self.ftest('floor(-1.23e167)', math.floor(-1.23e167), -1.23e167)
#self.assertEquals(math.ceil(INF), INF)
#self.assertEquals(math.ceil(NINF), NINF)
#self.assert_(math.isnan(math.floor(NAN)))
class TestFloor:
def __floor__(self):
return 42
class TestNoFloor:
pass
self.ftest('floor(TestFloor())', math.floor(TestFloor()), 42)
self.assertRaises(TypeError, math.floor, TestNoFloor())
t = TestNoFloor()
t.__floor__ = lambda *args: args
self.assertRaises(TypeError, math.floor, t)
self.assertRaises(TypeError, math.floor, t, 0)
def testFmod(self):
self.assertRaises(TypeError, math.fmod)
self.ftest('fmod(10,1)', math.fmod(10,1), 0)
self.ftest('fmod(10,0.5)', math.fmod(10,0.5), 0)
self.ftest('fmod(10,1.5)', math.fmod(10,1.5), 1)
self.ftest('fmod(-10,1)', math.fmod(-10,1), 0)
self.ftest('fmod(-10,0.5)', math.fmod(-10,0.5), 0)
self.ftest('fmod(-10,1.5)', math.fmod(-10,1.5), -1)
self.assert_(math.isnan(math.fmod(NAN, 1.)))
self.assert_(math.isnan(math.fmod(1., NAN)))
self.assert_(math.isnan(math.fmod(NAN, NAN)))
self.assertRaises(ValueError, math.fmod, 1., 0.)
self.assertRaises(ValueError, math.fmod, INF, 1.)
self.assertRaises(ValueError, math.fmod, NINF, 1.)
self.assertRaises(ValueError, math.fmod, INF, 0.)
self.assertEquals(math.fmod(3.0, INF), 3.0)
self.assertEquals(math.fmod(-3.0, INF), -3.0)
self.assertEquals(math.fmod(3.0, NINF), 3.0)
self.assertEquals(math.fmod(-3.0, NINF), -3.0)
self.assertEquals(math.fmod(0.0, 3.0), 0.0)
self.assertEquals(math.fmod(0.0, NINF), 0.0)
def testFrexp(self):
self.assertRaises(TypeError, math.frexp)
def testfrexp(name, result, expected):
(mant, exp), (emant, eexp) = result, expected
if abs(mant-emant) > eps or exp != eexp:
self.fail('%s returned %r, expected %r'%\
(name, result, expected))
testfrexp('frexp(-1)', math.frexp(-1), (-0.5, 1))
testfrexp('frexp(0)', math.frexp(0), (0, 0))
testfrexp('frexp(1)', math.frexp(1), (0.5, 1))
testfrexp('frexp(2)', math.frexp(2), (0.5, 2))
self.assertEquals(math.frexp(INF)[0], INF)
self.assertEquals(math.frexp(NINF)[0], NINF)
self.assert_(math.isnan(math.frexp(NAN)[0]))
def testHypot(self):
self.assertRaises(TypeError, math.hypot)
self.ftest('hypot(0,0)', math.hypot(0,0), 0)
self.ftest('hypot(3,4)', math.hypot(3,4), 5)
self.assertEqual(math.hypot(NAN, INF), INF)
self.assertEqual(math.hypot(INF, NAN), INF)
self.assertEqual(math.hypot(NAN, NINF), INF)
self.assertEqual(math.hypot(NINF, NAN), INF)
self.assert_(math.isnan(math.hypot(1.0, NAN)))
self.assert_(math.isnan(math.hypot(NAN, -2.0)))
def testLdexp(self):
self.assertRaises(TypeError, math.ldexp)
self.ftest('ldexp(0,1)', math.ldexp(0,1), 0)
self.ftest('ldexp(1,1)', math.ldexp(1,1), 2)
self.ftest('ldexp(1,-1)', math.ldexp(1,-1), 0.5)
self.ftest('ldexp(-1,1)', math.ldexp(-1,1), -2)
self.assertRaises(OverflowError, math.ldexp, 1., 1000000)
self.assertRaises(OverflowError, math.ldexp, -1., 1000000)
self.assertEquals(math.ldexp(1., -1000000), 0.)
self.assertEquals(math.ldexp(-1., -1000000), -0.)
self.assertEquals(math.ldexp(INF, 30), INF)
self.assertEquals(math.ldexp(NINF, -213), NINF)
self.assert_(math.isnan(math.ldexp(NAN, 0)))
# large second argument
for n in [10**5, 10**10, 10**20, 10**40]:
self.assertEquals(math.ldexp(INF, -n), INF)
self.assertEquals(math.ldexp(NINF, -n), NINF)
self.assertEquals(math.ldexp(1., -n), 0.)
self.assertEquals(math.ldexp(-1., -n), -0.)
self.assertEquals(math.ldexp(0., -n), 0.)
self.assertEquals(math.ldexp(-0., -n), -0.)
self.assert_(math.isnan(math.ldexp(NAN, -n)))
self.assertRaises(OverflowError, math.ldexp, 1., n)
self.assertRaises(OverflowError, math.ldexp, -1., n)
self.assertEquals(math.ldexp(0., n), 0.)
self.assertEquals(math.ldexp(-0., n), -0.)
self.assertEquals(math.ldexp(INF, n), INF)
self.assertEquals(math.ldexp(NINF, n), NINF)
self.assert_(math.isnan(math.ldexp(NAN, n)))
def testLog(self):
self.assertRaises(TypeError, math.log)
self.ftest('log(1/e)', math.log(1/math.e), -1)
self.ftest('log(1)', math.log(1), 0)
self.ftest('log(e)', math.log(math.e), 1)
self.ftest('log(32,2)', math.log(32,2), 5)
self.ftest('log(10**40, 10)', math.log(10**40, 10), 40)
self.ftest('log(10**40, 10**20)', math.log(10**40, 10**20), 2)
self.assertEquals(math.log(INF), INF)
self.assertRaises(ValueError, math.log, NINF)
self.assert_(math.isnan(math.log(NAN)))
def testLog1p(self):
self.assertRaises(TypeError, math.log1p)
self.ftest('log1p(1/e -1)', math.log1p(1/math.e-1), -1)
self.ftest('log1p(0)', math.log1p(0), 0)
self.ftest('log1p(e-1)', math.log1p(math.e-1), 1)
self.ftest('log1p(1)', math.log1p(1), math.log(2))
self.assertEquals(math.log1p(INF), INF)
self.assertRaises(ValueError, math.log1p, NINF)
self.assert_(math.isnan(math.log1p(NAN)))
n= 2**90
self.assertAlmostEquals(math.log1p(n), 62.383246250395075)
self.assertAlmostEquals(math.log1p(n), math.log1p(float(n)))
def testLog10(self):
self.assertRaises(TypeError, math.log10)
self.ftest('log10(0.1)', math.log10(0.1), -1)
self.ftest('log10(1)', math.log10(1), 0)
self.ftest('log10(10)', math.log10(10), 1)
self.assertEquals(math.log(INF), INF)
self.assertRaises(ValueError, math.log10, NINF)
self.assert_(math.isnan(math.log10(NAN)))
def testModf(self):
self.assertRaises(TypeError, math.modf)
def testmodf(name, result, expected):
(v1, v2), (e1, e2) = result, expected
if abs(v1-e1) > eps or abs(v2-e2):
self.fail('%s returned %r, expected %r'%\
(name, result, expected))
testmodf('modf(1.5)', math.modf(1.5), (0.5, 1.0))
testmodf('modf(-1.5)', math.modf(-1.5), (-0.5, -1.0))
self.assertEquals(math.modf(INF), (0.0, INF))
self.assertEquals(math.modf(NINF), (-0.0, NINF))
modf_nan = math.modf(NAN)
self.assert_(math.isnan(modf_nan[0]))
self.assert_(math.isnan(modf_nan[1]))
def testPow(self):
self.assertRaises(TypeError, math.pow)
self.ftest('pow(0,1)', math.pow(0,1), 0)
self.ftest('pow(1,0)', math.pow(1,0), 1)
self.ftest('pow(2,1)', math.pow(2,1), 2)
self.ftest('pow(2,-1)', math.pow(2,-1), 0.5)
self.assertEqual(math.pow(INF, 1), INF)
self.assertEqual(math.pow(NINF, 1), NINF)
self.assertEqual((math.pow(1, INF)), 1.)
self.assertEqual((math.pow(1, NINF)), 1.)
self.assert_(math.isnan(math.pow(NAN, 1)))
self.assert_(math.isnan(math.pow(2, NAN)))
self.assert_(math.isnan(math.pow(0, NAN)))
self.assertEqual(math.pow(1, NAN), 1)
# pow(0., x)
self.assertEqual(math.pow(0., INF), 0.)
self.assertEqual(math.pow(0., 3.), 0.)
self.assertEqual(math.pow(0., 2.3), 0.)
self.assertEqual(math.pow(0., 2.), 0.)
self.assertEqual(math.pow(0., 0.), 1.)
self.assertEqual(math.pow(0., -0.), 1.)
self.assertRaises(ValueError, math.pow, 0., -2.)
self.assertRaises(ValueError, math.pow, 0., -2.3)
self.assertRaises(ValueError, math.pow, 0., -3.)
self.assertRaises(ValueError, math.pow, 0., NINF)
self.assert_(math.isnan(math.pow(0., NAN)))
# pow(INF, x)
self.assertEqual(math.pow(INF, INF), INF)
self.assertEqual(math.pow(INF, 3.), INF)
self.assertEqual(math.pow(INF, 2.3), INF)
self.assertEqual(math.pow(INF, 2.), INF)
self.assertEqual(math.pow(INF, 0.), 1.)
self.assertEqual(math.pow(INF, -0.), 1.)
self.assertEqual(math.pow(INF, -2.), 0.)
self.assertEqual(math.pow(INF, -2.3), 0.)
self.assertEqual(math.pow(INF, -3.), 0.)
self.assertEqual(math.pow(INF, NINF), 0.)
self.assert_(math.isnan(math.pow(INF, NAN)))
# pow(-0., x)
self.assertEqual(math.pow(-0., INF), 0.)
self.assertEqual(math.pow(-0., 3.), -0.)
self.assertEqual(math.pow(-0., 2.3), 0.)
self.assertEqual(math.pow(-0., 2.), 0.)
self.assertEqual(math.pow(-0., 0.), 1.)
self.assertEqual(math.pow(-0., -0.), 1.)
self.assertRaises(ValueError, math.pow, -0., -2.)
self.assertRaises(ValueError, math.pow, -0., -2.3)
self.assertRaises(ValueError, math.pow, -0., -3.)
self.assertRaises(ValueError, math.pow, -0., NINF)
self.assert_(math.isnan(math.pow(-0., NAN)))
# pow(NINF, x)
self.assertEqual(math.pow(NINF, INF), INF)
self.assertEqual(math.pow(NINF, 3.), NINF)
self.assertEqual(math.pow(NINF, 2.3), INF)
self.assertEqual(math.pow(NINF, 2.), INF)
self.assertEqual(math.pow(NINF, 0.), 1.)
self.assertEqual(math.pow(NINF, -0.), 1.)
self.assertEqual(math.pow(NINF, -2.), 0.)
self.assertEqual(math.pow(NINF, -2.3), 0.)
self.assertEqual(math.pow(NINF, -3.), -0.)
self.assertEqual(math.pow(NINF, NINF), 0.)
self.assert_(math.isnan(math.pow(NINF, NAN)))
# pow(-1, x)
self.assertEqual(math.pow(-1., INF), 1.)
self.assertEqual(math.pow(-1., 3.), -1.)
self.assertRaises(ValueError, math.pow, -1., 2.3)
self.assertEqual(math.pow(-1., 2.), 1.)
self.assertEqual(math.pow(-1., 0.), 1.)
self.assertEqual(math.pow(-1., -0.), 1.)
self.assertEqual(math.pow(-1., -2.), 1.)
self.assertRaises(ValueError, math.pow, -1., -2.3)
self.assertEqual(math.pow(-1., -3.), -1.)
self.assertEqual(math.pow(-1., NINF), 1.)
self.assert_(math.isnan(math.pow(-1., NAN)))
# pow(1, x)
self.assertEqual(math.pow(1., INF), 1.)
self.assertEqual(math.pow(1., 3.), 1.)
self.assertEqual(math.pow(1., 2.3), 1.)
self.assertEqual(math.pow(1., 2.), 1.)
self.assertEqual(math.pow(1., 0.), 1.)
self.assertEqual(math.pow(1., -0.), 1.)
self.assertEqual(math.pow(1., -2.), 1.)
self.assertEqual(math.pow(1., -2.3), 1.)
self.assertEqual(math.pow(1., -3.), 1.)
self.assertEqual(math.pow(1., NINF), 1.)
self.assertEqual(math.pow(1., NAN), 1.)
# pow(x, 0) should be 1 for any x
self.assertEqual(math.pow(2.3, 0.), 1.)
self.assertEqual(math.pow(-2.3, 0.), 1.)
self.assertEqual(math.pow(NAN, 0.), 1.)
self.assertEqual(math.pow(2.3, -0.), 1.)
self.assertEqual(math.pow(-2.3, -0.), 1.)
self.assertEqual(math.pow(NAN, -0.), 1.)
# pow(x, y) is invalid if x is negative and y is not integral
self.assertRaises(ValueError, math.pow, -1., 2.3)
self.assertRaises(ValueError, math.pow, -15., -3.1)
# pow(x, NINF)
self.assertEqual(math.pow(1.9, NINF), 0.)
self.assertEqual(math.pow(1.1, NINF), 0.)
self.assertEqual(math.pow(0.9, NINF), INF)
self.assertEqual(math.pow(0.1, NINF), INF)
self.assertEqual(math.pow(-0.1, NINF), INF)
self.assertEqual(math.pow(-0.9, NINF), INF)
self.assertEqual(math.pow(-1.1, NINF), 0.)
self.assertEqual(math.pow(-1.9, NINF), 0.)
# pow(x, INF)
self.assertEqual(math.pow(1.9, INF), INF)
self.assertEqual(math.pow(1.1, INF), INF)
self.assertEqual(math.pow(0.9, INF), 0.)
self.assertEqual(math.pow(0.1, INF), 0.)
self.assertEqual(math.pow(-0.1, INF), 0.)
self.assertEqual(math.pow(-0.9, INF), 0.)
self.assertEqual(math.pow(-1.1, INF), INF)
self.assertEqual(math.pow(-1.9, INF), INF)
# pow(x, y) should work for x negative, y an integer
self.ftest('(-2.)**3.', math.pow(-2.0, 3.0), -8.0)
self.ftest('(-2.)**2.', math.pow(-2.0, 2.0), 4.0)
self.ftest('(-2.)**1.', math.pow(-2.0, 1.0), -2.0)
self.ftest('(-2.)**0.', math.pow(-2.0, 0.0), 1.0)
self.ftest('(-2.)**-0.', math.pow(-2.0, -0.0), 1.0)
self.ftest('(-2.)**-1.', math.pow(-2.0, -1.0), -0.5)
self.ftest('(-2.)**-2.', math.pow(-2.0, -2.0), 0.25)
self.ftest('(-2.)**-3.', math.pow(-2.0, -3.0), -0.125)
self.assertRaises(ValueError, math.pow, -2.0, -0.5)
self.assertRaises(ValueError, math.pow, -2.0, 0.5)
# the following tests have been commented out since they don't
# really belong here: the implementation of ** for floats is
# independent of the implemention of math.pow
#self.assertEqual(1**NAN, 1)
#self.assertEqual(1**INF, 1)
#self.assertEqual(1**NINF, 1)
#self.assertEqual(1**0, 1)
#self.assertEqual(1.**NAN, 1)
#self.assertEqual(1.**INF, 1)
#self.assertEqual(1.**NINF, 1)
#self.assertEqual(1.**0, 1)
def testRadians(self):
self.assertRaises(TypeError, math.radians)
self.ftest('radians(180)', math.radians(180), math.pi)
self.ftest('radians(90)', math.radians(90), math.pi/2)
self.ftest('radians(-45)', math.radians(-45), -math.pi/4)
def testSin(self):
self.assertRaises(TypeError, math.sin)
self.ftest('sin(0)', math.sin(0), 0)
self.ftest('sin(pi/2)', math.sin(math.pi/2), 1)
self.ftest('sin(-pi/2)', math.sin(-math.pi/2), -1)
try:
self.assert_(math.isnan(math.sin(INF)))
self.assert_(math.isnan(math.sin(NINF)))
except ValueError:
self.assertRaises(ValueError, math.sin, INF)
self.assertRaises(ValueError, math.sin, NINF)
self.assert_(math.isnan(math.sin(NAN)))
def testSinh(self):
self.assertRaises(TypeError, math.sinh)
self.ftest('sinh(0)', math.sinh(0), 0)
self.ftest('sinh(1)**2-cosh(1)**2', math.sinh(1)**2-math.cosh(1)**2, -1)
self.ftest('sinh(1)+sinh(-1)', math.sinh(1)+math.sinh(-1), 0)
self.assertEquals(math.sinh(INF), INF)
self.assertEquals(math.sinh(NINF), NINF)
self.assert_(math.isnan(math.sinh(NAN)))
def testSqrt(self):
self.assertRaises(TypeError, math.sqrt)
self.ftest('sqrt(0)', math.sqrt(0), 0)
self.ftest('sqrt(1)', math.sqrt(1), 1)
self.ftest('sqrt(4)', math.sqrt(4), 2)
self.assertEquals(math.sqrt(INF), INF)
self.assertRaises(ValueError, math.sqrt, NINF)
self.assert_(math.isnan(math.sqrt(NAN)))
def testSum(self):
# math.sum relies on exact rounding for correct operation.
# There's a known problem with IA32 floating-point that causes
# inexact rounding in some situations, and will cause the
# math.sum tests below to fail; see issue #2937. On non IEEE
# 754 platforms, and on IEEE 754 platforms that exhibit the
# problem described in issue #2937, we simply skip the whole
# test.
if not float.__getformat__("double").startswith("IEEE"):
return
# on IEEE 754 compliant machines, both of the expressions
# below should round to 10000000000000002.0.
if 1e16+2.999 != 1e16+2.9999:
return
# Python version of math.sum algorithm, for comparison
def msum(iterable):
"""Full precision sum of values in iterable. Returns the value of
the sum, rounded to the nearest representable floating-point number
using the round-half-to-even rule.
"""
# Stage 1: accumulate partials
partials = []
for x in iterable:
i = 0
for y in partials:
if abs(x) < abs(y):
x, y = y, x
hi = x + y
lo = y - (hi - x)
if lo:
partials[i] = lo
i += 1
x = hi
partials[i:] = [x] if x else []
# Stage 2: sum partials
if not partials:
return 0.0
# sum from the top, stopping as soon as the sum is inexact.
total = partials.pop()
while partials:
x = partials.pop()
old_total, total = total, total + x
error = x - (total - old_total)
if error != 0.0:
# adjust for correct rounding if necessary
if partials and (partials[-1] > 0.0) == (error > 0.0) and \
total + 2*error - total == 2*error:
total += 2*error
break
return total
from sys import float_info
maxfloat = float_info.max
twopow = 2.**(float_info.max_exp - 1)
test_values = [
([], 0.0),
([0.0], 0.0),
([1e100, 1.0, -1e100, 1e-100, 1e50, -1.0, -1e50], 1e-100),
([1e308, 1e308, -1e308], OverflowError),
([-1e308, 1e308, 1e308], 1e308),
([1e308, -1e308, 1e308], 1e308),
([2.0**1023, 2.0**1023, -2.0**1000], OverflowError),
([twopow, twopow, twopow, twopow, -twopow, -twopow, -twopow],
OverflowError),
([2.0**53, -0.5, -2.0**-54], 2.0**53-1.0),
([2.0**53, 1.0, 2.0**-100], 2.0**53+2.0),
([2.0**53+10.0, 1.0, 2.0**-100], 2.0**53+12.0),
([2.0**53-4.0, 0.5, 2.0**-54], 2.0**53-3.0),
([2.0**1023-2.0**970, -1.0, 2.0**1023], OverflowError),
([maxfloat, maxfloat*2.**-54], maxfloat),
([maxfloat, maxfloat*2.**-53], OverflowError),
([1./n for n in range(1, 1001)], 7.4854708605503451),
([(-1.)**n/n for n in range(1, 1001)], -0.69264743055982025),
([1.7**(i+1)-1.7**i for i in range(1000)] + [-1.7**1000], -1.0),
([INF, -INF, NAN], ValueError),
([NAN, INF, -INF], ValueError),
([INF, NAN, INF], ValueError),
([INF, INF], OverflowError),
([INF, -INF], ValueError),
([-INF, 1e308, 1e308, -INF], OverflowError),
([2.0**1023-2.0**970, 0.0, 2.0**1023], OverflowError),
([2.0**1023-2.0**970, 1.0, 2.0**1023], OverflowError),
([2.0**1023, 2.0**1023], OverflowError),
([2.0**1023, 2.0**1023, -1.0], OverflowError),
([twopow, twopow, twopow, twopow, -twopow, -twopow],
OverflowError),
([twopow, twopow, twopow, twopow, -twopow, twopow], OverflowError),
([-twopow, -twopow, -twopow, -twopow], OverflowError),
([2.**1023, 2.**1023, -2.**971], OverflowError),
([2.**1023, 2.**1023, -2.**970], OverflowError),
([-2.**970, 2.**1023, 2.**1023, -2.**-1074], OverflowError),
([ 2.**1023, 2.**1023, -2.**970, 2.**-1074], OverflowError),
([-2.**1023, 2.**971, -2.**1023], -maxfloat),
([-2.**1023, -2.**1023, 2.**970], OverflowError),
([-2.**1023, -2.**1023, 2.**970, 2.**-1074], OverflowError),
([-2.**-1074, -2.**1023, -2.**1023, 2.**970], OverflowError),
([2.**930, -2.**980, 2.**1023, 2.**1023, twopow, -twopow],
OverflowError),
([2.**1023, 2.**1023, -1e307], OverflowError),
([1e16, 1., 1e-16], 10000000000000002.0),
([1e16-2., 1.-2.**-53, -(1e16-2.), -(1.-2.**-53)], 0.0),
]
for i, (vals, s) in enumerate(test_values):
if isinstance(s, type) and issubclass(s, Exception):
try:
m = math.sum(vals)
except s:
pass
else:
self.fail("test %d failed: got %r, expected %r "
"for math.sum(%.100r)" %
(i, m, s.__name__, vals))
else:
try:
self.assertEqual(math.sum(vals), s)
except OverflowError:
self.fail("test %d failed: got OverflowError, expected %r "
"for math.sum(%.100r)" % (i, s, vals))
except ValueError:
self.fail("test %d failed: got ValueError, expected %r "
"for math.sum(%.100r)" % (i, s, vals))
# compare with output of msum above, but only when
# result isn't an IEEE special or an exception
if not math.isinf(s) and not math.isnan(s):
self.assertEqual(msum(vals), s)
from random import random, gauss, shuffle
for j in range(1000):
vals = [7, 1e100, -7, -1e100, -9e-20, 8e-20] * 10
s = 0
for i in range(200):
v = gauss(0, random()) ** 7 - s
s += v
vals.append(v)
shuffle(vals)
s = msum(vals)
self.assertEqual(msum(vals), math.sum(vals))
def testTan(self):
self.assertRaises(TypeError, math.tan)
self.ftest('tan(0)', math.tan(0), 0)
self.ftest('tan(pi/4)', math.tan(math.pi/4), 1)
self.ftest('tan(-pi/4)', math.tan(-math.pi/4), -1)
try:
self.assert_(math.isnan(math.tan(INF)))
self.assert_(math.isnan(math.tan(NINF)))
except:
self.assertRaises(ValueError, math.tan, INF)
self.assertRaises(ValueError, math.tan, NINF)
self.assert_(math.isnan(math.tan(NAN)))
def testTanh(self):
self.assertRaises(TypeError, math.tanh)
self.ftest('tanh(0)', math.tanh(0), 0)
self.ftest('tanh(1)+tanh(-1)', math.tanh(1)+math.tanh(-1), 0)
self.ftest('tanh(inf)', math.tanh(INF), 1)
self.ftest('tanh(-inf)', math.tanh(NINF), -1)
self.assert_(math.isnan(math.tanh(NAN)))
# check that tanh(-0.) == -0. on IEEE 754 systems
if float.__getformat__("double").startswith("IEEE"):
self.assertEqual(math.tanh(-0.), -0.)
self.assertEqual(math.copysign(1., math.tanh(-0.)),
math.copysign(1., -0.))
def test_trunc(self):
self.assertEqual(math.trunc(1), 1)
self.assertEqual(math.trunc(-1), -1)
self.assertEqual(type(math.trunc(1)), int)
self.assertEqual(type(math.trunc(1.5)), int)
self.assertEqual(math.trunc(1.5), 1)
self.assertEqual(math.trunc(-1.5), -1)
self.assertEqual(math.trunc(1.999999), 1)
self.assertEqual(math.trunc(-1.999999), -1)
self.assertEqual(math.trunc(-0.999999), -0)
self.assertEqual(math.trunc(-100.999), -100)
class TestTrunc(object):
def __trunc__(self):
return 23
class TestNoTrunc(object):
pass
self.assertEqual(math.trunc(TestTrunc()), 23)
self.assertRaises(TypeError, math.trunc)
self.assertRaises(TypeError, math.trunc, 1, 2)
self.assertRaises(TypeError, math.trunc, TestNoTrunc())
# XXX Doesn't work because the method is looked up on
# the type only.
#t = TestNoTrunc()
#t.__trunc__ = lambda *args: args
#self.assertEquals((), math.trunc(t))
#self.assertRaises(TypeError, math.trunc, t, 0)
def testCopysign(self):
self.assertEqual(math.copysign(1, 42), 1.0)
self.assertEqual(math.copysign(0., 42), 0.0)
self.assertEqual(math.copysign(1., -42), -1.0)
self.assertEqual(math.copysign(3, 0.), 3.0)
self.assertEqual(math.copysign(4., -0.), -4.0)
def testIsnan(self):
self.assert_(math.isnan(float("nan")))
self.assert_(math.isnan(float("inf")* 0.))
self.failIf(math.isnan(float("inf")))
self.failIf(math.isnan(0.))
self.failIf(math.isnan(1.))
def testIsinf(self):
self.assert_(math.isinf(float("inf")))
self.assert_(math.isinf(float("-inf")))
self.assert_(math.isinf(1E400))
self.assert_(math.isinf(-1E400))
self.failIf(math.isinf(float("nan")))
self.failIf(math.isinf(0.))
self.failIf(math.isinf(1.))
# RED_FLAG 16-Oct-2000 Tim
# While 2.0 is more consistent about exceptions than previous releases, it
# still fails this part of the test on some platforms. For now, we only
# *run* test_exceptions() in verbose mode, so that this isn't normally
# tested.
if verbose:
def test_exceptions(self):
try:
x = math.exp(-1000000000)
except:
# mathmodule.c is failing to weed out underflows from libm, or
# we've got an fp format with huge dynamic range
self.fail("underflowing exp() should not have raised "
"an exception")
if x != 0:
self.fail("underflowing exp() should have returned 0")
# If this fails, probably using a strict IEEE-754 conforming libm, and x
# is +Inf afterwards. But Python wants overflows detected by default.
try:
x = math.exp(1000000000)
except OverflowError:
pass
else:
self.fail("overflowing exp() didn't trigger OverflowError")
# If this fails, it could be a puzzle. One odd possibility is that
# mathmodule.c's macros are getting confused while comparing
# Inf (HUGE_VAL) to a NaN, and artificially setting errno to ERANGE
# as a result (and so raising OverflowError instead).
try:
x = math.sqrt(-1.0)
except ValueError:
pass
else:
self.fail("sqrt(-1) didn't raise ValueError")
def test_testfile(self):
if not float.__getformat__("double").startswith("IEEE"):
return
for id, fn, ar, ai, er, ei, flags in parse_testfile(test_file):
# Skip if either the input or result is complex, or if
# flags is nonempty
if ai != 0. or ei != 0. or flags:
continue
if fn in ['rect', 'polar']:
# no real versions of rect, polar
continue
func = getattr(math, fn)
try:
result = func(ar)
except ValueError as exc:
message = (("Unexpected ValueError: %s\n " +
"in test %s:%s(%r)\n") % (exc.args[0], id, fn, ar))
self.fail(message)
except OverflowError:
message = ("Unexpected OverflowError in " +
"test %s:%s(%r)\n" % (id, fn, ar))
self.fail(message)
self.ftest("%s:%s(%r)" % (id, fn, ar), result, er)
def test_main():
from doctest import DocFileSuite
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(MathTests))
suite.addTest(DocFileSuite("ieee754.txt"))
run_unittest(suite)
if __name__ == '__main__':
test_main()