PageRenderTime 53ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 1ms

/rpython/rlib/test/test_rfloat.py

https://bitbucket.org/pypy/pypy/
Python | 276 lines | 222 code | 33 blank | 21 comment | 40 complexity | 22da0e5e5c6acfdc5d82618b117efb4d MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import sys, py
  2. from rpython.rlib.rfloat import float_as_rbigint_ratio
  3. from rpython.rlib.rfloat import copysign
  4. from rpython.rlib.rfloat import round_away
  5. from rpython.rlib.rfloat import round_double
  6. from rpython.rlib.rfloat import erf, erfc, gamma, lgamma, isnan
  7. from rpython.rlib.rfloat import ulps_check, acc_check
  8. from rpython.rlib.rfloat import string_to_float
  9. from rpython.rlib.rbigint import rbigint
  10. def test_copysign():
  11. assert copysign(1, 1) == 1
  12. assert copysign(-1, 1) == 1
  13. assert copysign(-1, -1) == -1
  14. assert copysign(1, -1) == -1
  15. assert copysign(1, -0.) == -1
  16. def test_round_away():
  17. assert round_away(.1) == 0.
  18. assert round_away(.5) == 1.
  19. assert round_away(.7) == 1.
  20. assert round_away(1.) == 1.
  21. assert round_away(-.5) == -1.
  22. assert round_away(-.1) == 0.
  23. assert round_away(-.7) == -1.
  24. assert round_away(0.) == 0.
  25. def test_round_double():
  26. def almost_equal(x, y):
  27. assert round(abs(x-y), 7) == 0
  28. almost_equal(round_double(0.125, 2), 0.13)
  29. almost_equal(round_double(0.375, 2), 0.38)
  30. almost_equal(round_double(0.625, 2), 0.63)
  31. almost_equal(round_double(0.875, 2), 0.88)
  32. almost_equal(round_double(-0.125, 2), -0.13)
  33. almost_equal(round_double(-0.375, 2), -0.38)
  34. almost_equal(round_double(-0.625, 2), -0.63)
  35. almost_equal(round_double(-0.875, 2), -0.88)
  36. almost_equal(round_double(0.25, 1), 0.3)
  37. almost_equal(round_double(0.75, 1), 0.8)
  38. almost_equal(round_double(-0.25, 1), -0.3)
  39. almost_equal(round_double(-0.75, 1), -0.8)
  40. round_double(-6.5, 0) == -7.0
  41. round_double(-5.5, 0) == -6.0
  42. round_double(-1.5, 0) == -2.0
  43. round_double(-0.5, 0) == -1.0
  44. round_double(0.5, 0) == 1.0
  45. round_double(1.5, 0) == 2.0
  46. round_double(2.5, 0) == 3.0
  47. round_double(3.5, 0) == 4.0
  48. round_double(4.5, 0) == 5.0
  49. round_double(5.5, 0) == 6.0
  50. round_double(6.5, 0) == 7.0
  51. round_double(-25.0, -1) == -30.0
  52. round_double(-15.0, -1) == -20.0
  53. round_double(-5.0, -1) == -10.0
  54. round_double(5.0, -1) == 10.0
  55. round_double(15.0, -1) == 20.0
  56. round_double(25.0, -1) == 30.0
  57. round_double(35.0, -1) == 40.0
  58. round_double(45.0, -1) == 50.0
  59. round_double(55.0, -1) == 60.0
  60. round_double(65.0, -1) == 70.0
  61. round_double(75.0, -1) == 80.0
  62. round_double(85.0, -1) == 90.0
  63. round_double(95.0, -1) == 100.0
  64. round_double(12325.0, -1) == 12330.0
  65. round_double(350.0, -2) == 400.0
  66. round_double(450.0, -2) == 500.0
  67. almost_equal(round_double(0.5e21, -21), 1e21)
  68. almost_equal(round_double(1.5e21, -21), 2e21)
  69. almost_equal(round_double(2.5e21, -21), 3e21)
  70. almost_equal(round_double(5.5e21, -21), 6e21)
  71. almost_equal(round_double(8.5e21, -21), 9e21)
  72. almost_equal(round_double(-1.5e22, -22), -2e22)
  73. almost_equal(round_double(-0.5e22, -22), -1e22)
  74. almost_equal(round_double(0.5e22, -22), 1e22)
  75. almost_equal(round_double(1.5e22, -22), 2e22)
  76. def test_round_half_even():
  77. from rpython.rlib import rfloat
  78. func = rfloat.round_double
  79. # 2.x behavior
  80. assert func(2.5, 0, False) == 3.0
  81. # 3.x behavior
  82. assert func(2.5, 0, True) == 2.0
  83. def test_float_as_rbigint_ratio():
  84. for f, ratio in [
  85. (0.875, (7, 8)),
  86. (-0.875, (-7, 8)),
  87. (0.0, (0, 1)),
  88. (11.5, (23, 2)),
  89. ]:
  90. num, den = float_as_rbigint_ratio(f)
  91. assert num.eq(rbigint.fromint(ratio[0]))
  92. assert den.eq(rbigint.fromint(ratio[1]))
  93. with py.test.raises(OverflowError):
  94. float_as_rbigint_ratio(float('inf'))
  95. with py.test.raises(OverflowError):
  96. float_as_rbigint_ratio(float('-inf'))
  97. with py.test.raises(ValueError):
  98. float_as_rbigint_ratio(float('nan'))
  99. def test_mtestfile():
  100. from rpython.rlib import rfloat
  101. import zipfile
  102. import os
  103. def _parse_mtestfile(fname):
  104. """Parse a file with test values
  105. -- starts a comment
  106. blank lines, or lines containing only a comment, are ignored
  107. other lines are expected to have the form
  108. id fn arg -> expected [flag]*
  109. """
  110. with open(fname) as fp:
  111. for line in fp:
  112. # strip comments, and skip blank lines
  113. if '--' in line:
  114. line = line[:line.index('--')]
  115. if not line.strip():
  116. continue
  117. lhs, rhs = line.split('->')
  118. id, fn, arg = lhs.split()
  119. rhs_pieces = rhs.split()
  120. exp = rhs_pieces[0]
  121. flags = rhs_pieces[1:]
  122. yield (id, fn, float(arg), float(exp), flags)
  123. ALLOWED_ERROR = 20 # permitted error, in ulps
  124. fail_fmt = "{}:{}({!r}): expected {!r}, got {!r}"
  125. failures = []
  126. math_testcases = os.path.join(os.path.dirname(__file__),
  127. "math_testcases.txt")
  128. for id, fn, arg, expected, flags in _parse_mtestfile(math_testcases):
  129. func = getattr(rfloat, fn)
  130. if 'invalid' in flags or 'divide-by-zero' in flags:
  131. expected = 'ValueError'
  132. elif 'overflow' in flags:
  133. expected = 'OverflowError'
  134. try:
  135. got = func(arg)
  136. except ValueError:
  137. got = 'ValueError'
  138. except OverflowError:
  139. got = 'OverflowError'
  140. accuracy_failure = None
  141. if isinstance(got, float) and isinstance(expected, float):
  142. if isnan(expected) and isnan(got):
  143. continue
  144. if not isnan(expected) and not isnan(got):
  145. if fn == 'lgamma':
  146. # we use a weaker accuracy test for lgamma;
  147. # lgamma only achieves an absolute error of
  148. # a few multiples of the machine accuracy, in
  149. # general.
  150. accuracy_failure = acc_check(expected, got,
  151. rel_err = 5e-15,
  152. abs_err = 5e-15)
  153. elif fn == 'erfc':
  154. # erfc has less-than-ideal accuracy for large
  155. # arguments (x ~ 25 or so), mainly due to the
  156. # error involved in computing exp(-x*x).
  157. #
  158. # XXX Would be better to weaken this test only
  159. # for large x, instead of for all x.
  160. accuracy_failure = ulps_check(expected, got, 2000)
  161. else:
  162. accuracy_failure = ulps_check(expected, got, 20)
  163. if accuracy_failure is None:
  164. continue
  165. if isinstance(got, str) and isinstance(expected, str):
  166. if got == expected:
  167. continue
  168. fail_msg = fail_fmt.format(id, fn, arg, expected, got)
  169. if accuracy_failure is not None:
  170. fail_msg += ' ({})'.format(accuracy_failure)
  171. failures.append(fail_msg)
  172. assert not failures
  173. def test_gamma_overflow_translated():
  174. from rpython.translator.c.test.test_genc import compile
  175. def wrapper(arg):
  176. try:
  177. return gamma(arg)
  178. except OverflowError:
  179. return -42
  180. f = compile(wrapper, [float])
  181. assert f(10.0) == 362880.0
  182. assert f(1720.0) == -42
  183. assert f(172.0) == -42
  184. def test_string_to_float():
  185. from rpython.rlib.rstring import ParseStringError
  186. import random
  187. assert string_to_float('0') == 0.0
  188. assert string_to_float('1') == 1.0
  189. assert string_to_float('-1.5') == -1.5
  190. assert string_to_float('1.5E2') == 150.0
  191. assert string_to_float('2.5E-1') == 0.25
  192. assert string_to_float('1e1111111111111') == float('1e1111111111111')
  193. assert string_to_float('1e-1111111111111') == float('1e-1111111111111')
  194. assert string_to_float('-1e1111111111111') == float('-1e1111111111111')
  195. assert string_to_float('-1e-1111111111111') == float('-1e-1111111111111')
  196. assert string_to_float('1e111111111111111111111') == float('1e111111111111111111111')
  197. assert string_to_float('1e-111111111111111111111') == float('1e-111111111111111111111')
  198. assert string_to_float('-1e111111111111111111111') == float('-1e111111111111111111111')
  199. assert string_to_float('-1e-111111111111111111111') == float('-1e-111111111111111111111')
  200. valid_parts = [['', ' ', ' \f\n\r\t\v'],
  201. ['', '+', '-'],
  202. ['00', '90', '.5', '2.4', '3.', '0.07',
  203. '12.3489749871982471987198371293717398256187563298638726'
  204. '2187362820947193247129871083561249818451804287437824015'
  205. '013816418758104762348932657836583048761487632840726386'],
  206. ['', 'e0', 'E+1', 'E-01', 'E42'],
  207. ['', ' ', ' \f\n\r\t\v'],
  208. ]
  209. invalid_parts = [['#'],
  210. ['++', '+-', '-+', '--'],
  211. ['', '1.2.3', '.', '5..6'],
  212. ['E+', 'E-', 'e', 'e++', 'E++2'],
  213. ['#'],
  214. ]
  215. for part0 in valid_parts[0]:
  216. for part1 in valid_parts[1]:
  217. for part2 in valid_parts[2]:
  218. for part3 in valid_parts[3]:
  219. for part4 in valid_parts[4]:
  220. s = part0+part1+part2+part3+part4
  221. assert (abs(string_to_float(s) - float(s)) <=
  222. 1E-13 * abs(float(s)))
  223. for j in range(len(invalid_parts)):
  224. for invalid in invalid_parts[j]:
  225. for i in range(20):
  226. parts = [random.choice(lst) for lst in valid_parts]
  227. parts[j] = invalid
  228. s = ''.join(parts)
  229. print repr(s)
  230. if s.strip(): # empty s raises OperationError directly
  231. py.test.raises(ParseStringError, string_to_float, s)
  232. py.test.raises(ParseStringError, string_to_float, "")
  233. def test_log2():
  234. from rpython.rlib import rfloat
  235. assert rfloat.log2(1.0) == 0.0
  236. assert rfloat.log2(2.0) == 1.0
  237. assert rfloat.log2(2.0**1023) == 1023.0
  238. assert 1.584 < rfloat.log2(3.0) < 1.585
  239. py.test.raises(ValueError, rfloat.log2, 0)
  240. py.test.raises(ValueError, rfloat.log2, -1)