/pypy/module/math/test/test_direct.py

https://github.com/alemacgo/pypy · Python · 242 lines · 205 code · 23 blank · 14 comment · 32 complexity · 2d94eff9137c081c44fef717fdad4f61 MD5 · raw file

  1. """ Try to test systematically all cases of the math module.
  2. """
  3. import py, sys, math
  4. from pypy.rlib import rfloat
  5. from pypy.rlib.rfloat import isinf, isnan, INFINITY, NAN
  6. consistent_host = True
  7. if '__pypy__' not in sys.builtin_module_names:
  8. if sys.version_info < (2, 6):
  9. consistent_host = False
  10. def positiveinf(x):
  11. return isinf(x) and x > 0.0
  12. def negativeinf(x):
  13. return isinf(x) and x < 0.0
  14. def finite(x):
  15. return not isinf(x) and not isnan(x)
  16. unary_math_functions = ['acos', 'asin', 'atan',
  17. 'ceil', 'cos', 'cosh', 'exp', 'fabs', 'floor',
  18. 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'log', 'log10',
  19. 'acosh', 'asinh', 'atanh', 'log1p', 'expm1']
  20. binary_math_functions = ['atan2', 'fmod', 'hypot', 'pow']
  21. class MathTests:
  22. REGCASES = []
  23. for name in unary_math_functions:
  24. try:
  25. input, output = (0.3,), getattr(math, name)(0.3)
  26. except AttributeError:
  27. # cannot test this function
  28. continue
  29. except ValueError:
  30. input, output = (1.3,), getattr(math, name)(1.3)
  31. REGCASES.append((name, input, output))
  32. IRREGCASES = [
  33. ('atan2', (0.31, 0.123), math.atan2(0.31, 0.123)),
  34. ('fmod', (0.31, 0.123), math.fmod(0.31, 0.123)),
  35. ('hypot', (0.31, 0.123), math.hypot(0.31, 0.123)),
  36. ('pow', (0.31, 0.123), math.pow(0.31, 0.123)),
  37. ('pow', (-0.31, 0.123), ValueError),
  38. ('pow', (-0.5, 2.0), 0.25),
  39. ('pow', (-0.5, 1.0), -0.5),
  40. ('pow', (-0.5, 0.0), 1.0),
  41. ('pow', (-0.5, -1.0), -2.0),
  42. ('ldexp', (3.375, 2), 13.5),
  43. ('ldexp', (1.0, -10000), 0.0), # underflow
  44. ('frexp', (-1.25,), lambda x: x == (-0.625, 1)),
  45. ('modf', (4.25,), lambda x: x == (0.25, 4.0)),
  46. ('modf', (-4.25,), lambda x: x == (-0.25, -4.0)),
  47. ]
  48. OVFCASES = [
  49. ('cosh', (9999.9,), OverflowError),
  50. ('sinh', (9999.9,), OverflowError),
  51. ('exp', (9999.9,), OverflowError),
  52. ('pow', (10.0, 40000.0), OverflowError),
  53. ('ldexp', (10.0, 40000), OverflowError),
  54. ('log', (0.0,), ValueError),
  55. ('log', (-1.,), ValueError),
  56. ('log10', (0.0,), ValueError),
  57. ]
  58. INFCASES = [
  59. ('acos', (INFINITY,), ValueError),
  60. ('acos', (-INFINITY,), ValueError),
  61. ('asin', (INFINITY,), ValueError),
  62. ('asin', (-INFINITY,), ValueError),
  63. ('atan', (INFINITY,), math.pi / 2),
  64. ('atan', (-INFINITY,), -math.pi / 2),
  65. ('atanh', (INFINITY,), ValueError),
  66. ('atanh', (-INFINITY,), ValueError),
  67. ('ceil', (INFINITY,), positiveinf),
  68. ('ceil', (-INFINITY,), negativeinf),
  69. ('cos', (INFINITY,), ValueError),
  70. ('cos', (-INFINITY,), ValueError),
  71. ('cosh', (INFINITY,), positiveinf),
  72. ('cosh', (-INFINITY,), positiveinf),
  73. ('exp', (INFINITY,), positiveinf),
  74. ('exp', (-INFINITY,), 0.0),
  75. ('fabs', (INFINITY,), positiveinf),
  76. ('fabs', (-INFINITY,), positiveinf),
  77. ('floor', (INFINITY,), positiveinf),
  78. ('floor', (-INFINITY,), negativeinf),
  79. ('sin', (INFINITY,), ValueError),
  80. ('sin', (-INFINITY,), ValueError),
  81. ('sinh', (INFINITY,), positiveinf),
  82. ('sinh', (-INFINITY,), negativeinf),
  83. ('sqrt', (INFINITY,), positiveinf),
  84. ('sqrt', (-INFINITY,), ValueError),
  85. ('tan', (INFINITY,), ValueError),
  86. ('tan', (-INFINITY,), ValueError),
  87. ('tanh', (INFINITY,), 1.0),
  88. ('tanh', (-INFINITY,), -1.0),
  89. ('log', (INFINITY,), positiveinf),
  90. ('log', (-INFINITY,), ValueError),
  91. ('log10', (INFINITY,), positiveinf),
  92. ('log10', (-INFINITY,), ValueError),
  93. ('frexp', (INFINITY,), lambda x: isinf(x[0])),
  94. ('ldexp', (INFINITY, 3), positiveinf),
  95. ('ldexp', (-INFINITY, 3), negativeinf),
  96. ('modf', (INFINITY,), lambda x: positiveinf(x[1])),
  97. ('modf', (-INFINITY,), lambda x: negativeinf(x[1])),
  98. ('pow', (INFINITY, 0.0), 1.0),
  99. ('pow', (INFINITY, 0.001), positiveinf),
  100. ('pow', (INFINITY, -0.001), 0.0),
  101. ('pow', (-INFINITY, 0.0), 1.0),
  102. ('pow', (-INFINITY, 0.001), positiveinf),
  103. ('pow', (-INFINITY, -0.001), 0.0),
  104. ('pow', (-INFINITY, 3.0), negativeinf),
  105. ('pow', (-INFINITY, 6.0), positiveinf),
  106. ('pow', (-INFINITY, -13.0), -0.0),
  107. ('pow', (-INFINITY, -128.0), 0.0),
  108. ('pow', (1.001, INFINITY), positiveinf),
  109. ('pow', (1.0, INFINITY), 1.0),
  110. ('pow', (0.999, INFINITY), 0.0),
  111. ('pow', (-0.999,INFINITY), 0.0),
  112. #('pow', (-1.0, INFINITY), 1.0, but strange, could also be -1.0),
  113. ('pow', (-1.001,INFINITY), positiveinf),
  114. ('pow', (1.001, -INFINITY), 0.0),
  115. ('pow', (1.0, -INFINITY), 1.0),
  116. #('pow', (0.999, -INFINITY), positiveinf, but get OverflowError),
  117. #('pow', (INFINITY, INFINITY), positiveinf, but get OverflowError),
  118. ('pow', (INFINITY, -INFINITY), 0.0),
  119. ('pow', (-INFINITY, INFINITY), positiveinf),
  120. ]
  121. IRREGERRCASES = [
  122. #
  123. ('atan2', (INFINITY, -2.3), math.pi / 2),
  124. ('atan2', (INFINITY, 0.0), math.pi / 2),
  125. ('atan2', (INFINITY, 3.0), math.pi / 2),
  126. #('atan2', (INFINITY, INFINITY), ?strange),
  127. ('atan2', (2.1, INFINITY), 0.0),
  128. ('atan2', (0.0, INFINITY), 0.0),
  129. ('atan2', (-0.1, INFINITY), -0.0),
  130. ('atan2', (-INFINITY, 0.4), -math.pi / 2),
  131. ('atan2', (2.1, -INFINITY), math.pi),
  132. ('atan2', (0.0, -INFINITY), math.pi),
  133. ('atan2', (-0.1, -INFINITY), -math.pi),
  134. #
  135. ('fmod', (INFINITY, 1.0), ValueError),
  136. ('fmod', (1.0, INFINITY), 1.0),
  137. ('fmod', (1.0, -INFINITY), 1.0),
  138. ('fmod', (INFINITY, INFINITY), ValueError),
  139. #
  140. ('hypot', (-INFINITY, 1.0), positiveinf),
  141. ('hypot', (-2.3, -INFINITY), positiveinf),
  142. ]
  143. binary_math_functions = ['atan2', 'fmod', 'hypot', 'pow']
  144. NANCASES1 = [
  145. (name, (NAN,), isnan) for name in unary_math_functions]
  146. NANCASES2 = [
  147. (name, (NAN, 0.1), isnan) for name in binary_math_functions]
  148. NANCASES3 = [
  149. (name, (-0.2, NAN), isnan) for name in binary_math_functions]
  150. NANCASES4 = [
  151. (name, (NAN, -INFINITY), isnan) for name in binary_math_functions
  152. if name != 'hypot']
  153. NANCASES5 = [
  154. (name, (INFINITY, NAN), isnan) for name in binary_math_functions
  155. if name != 'hypot']
  156. NANCASES6 = [
  157. ('frexp', (NAN,), lambda x: isnan(x[0])),
  158. ('ldexp', (NAN, 2), isnan),
  159. ('hypot', (NAN, INFINITY), positiveinf),
  160. ('hypot', (NAN, -INFINITY), positiveinf),
  161. ('hypot', (INFINITY, NAN), positiveinf),
  162. ('hypot', (-INFINITY, NAN), positiveinf),
  163. ('modf', (NAN,), lambda x: (isnan(x[0]) and isnan(x[1]))),
  164. ]
  165. # The list of test cases. Note that various tests import this,
  166. # notably in rpython/lltypesystem/module and in translator/c/test.
  167. TESTCASES = (REGCASES + IRREGCASES + OVFCASES + INFCASES + IRREGERRCASES
  168. + NANCASES1 + NANCASES2 + NANCASES3 + NANCASES4 + NANCASES5
  169. + NANCASES6)
  170. class TestDirect(MathTests):
  171. pass
  172. def get_tester(expected):
  173. if type(expected) is type(Exception):
  174. def tester(value):
  175. return False
  176. elif callable(expected):
  177. def tester(value):
  178. ok = expected(value)
  179. assert isinstance(ok, bool)
  180. return ok
  181. else:
  182. assert finite(expected), "badly written test"
  183. def tester(got):
  184. gotsign = expectedsign = 1
  185. if got < 0.0: gotsign = -gotsign
  186. if expected < 0.0: expectedsign = -expectedsign
  187. return finite(got) and (got == expected and
  188. gotsign == expectedsign)
  189. return tester
  190. def do_test(fn, fnname, args, expected):
  191. repr = "%s(%s)" % (fnname, ', '.join(map(str, args)))
  192. try:
  193. got = fn(*args)
  194. except ValueError:
  195. assert expected == ValueError, "%s: got a ValueError" % (repr,)
  196. except OverflowError:
  197. assert expected == OverflowError, "%s: got an OverflowError" % (
  198. repr,)
  199. else:
  200. if not get_tester(expected)(got):
  201. raise AssertionError("%r: got %s" % (repr, got))
  202. def make_test_case((fnname, args, expected), dict):
  203. #
  204. def test_func(self):
  205. if not consistent_host:
  206. py.test.skip("inconsistent behavior before 2.6")
  207. try:
  208. fn = getattr(math, fnname)
  209. except AttributeError:
  210. fn = getattr(rfloat, fnname)
  211. do_test(fn, fnname, args, expected)
  212. #
  213. dict[fnname] = dict.get(fnname, 0) + 1
  214. testname = 'test_%s_%d' % (fnname, dict[fnname])
  215. test_func.func_name = testname
  216. setattr(TestDirect, testname, test_func)
  217. _d = {}
  218. for testcase in TestDirect.TESTCASES:
  219. make_test_case(testcase, _d)