You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

250 lines
9.4 KiB

  1. # Copyright (c) 2010 Python Software Foundation. All Rights Reserved.
  2. # Adapted from Python's Lib/test/test_strtod.py (by Mark Dickinson)
  3. # More test cases for deccheck.py.
  4. import random
  5. TEST_SIZE = 2
  6. def test_short_halfway_cases():
  7. # exact halfway cases with a small number of significant digits
  8. for k in 0, 5, 10, 15, 20:
  9. # upper = smallest integer >= 2**54/5**k
  10. upper = -(-2**54//5**k)
  11. # lower = smallest odd number >= 2**53/5**k
  12. lower = -(-2**53//5**k)
  13. if lower % 2 == 0:
  14. lower += 1
  15. for i in range(10 * TEST_SIZE):
  16. # Select a random odd n in [2**53/5**k,
  17. # 2**54/5**k). Then n * 10**k gives a halfway case
  18. # with small number of significant digits.
  19. n, e = random.randrange(lower, upper, 2), k
  20. # Remove any additional powers of 5.
  21. while n % 5 == 0:
  22. n, e = n // 5, e + 1
  23. assert n % 10 in (1, 3, 7, 9)
  24. # Try numbers of the form n * 2**p2 * 10**e, p2 >= 0,
  25. # until n * 2**p2 has more than 20 significant digits.
  26. digits, exponent = n, e
  27. while digits < 10**20:
  28. s = '{}e{}'.format(digits, exponent)
  29. yield s
  30. # Same again, but with extra trailing zeros.
  31. s = '{}e{}'.format(digits * 10**40, exponent - 40)
  32. yield s
  33. digits *= 2
  34. # Try numbers of the form n * 5**p2 * 10**(e - p5), p5
  35. # >= 0, with n * 5**p5 < 10**20.
  36. digits, exponent = n, e
  37. while digits < 10**20:
  38. s = '{}e{}'.format(digits, exponent)
  39. yield s
  40. # Same again, but with extra trailing zeros.
  41. s = '{}e{}'.format(digits * 10**40, exponent - 40)
  42. yield s
  43. digits *= 5
  44. exponent -= 1
  45. def test_halfway_cases():
  46. # test halfway cases for the round-half-to-even rule
  47. for i in range(1000):
  48. for j in range(TEST_SIZE):
  49. # bit pattern for a random finite positive (or +0.0) float
  50. bits = random.randrange(2047*2**52)
  51. # convert bit pattern to a number of the form m * 2**e
  52. e, m = divmod(bits, 2**52)
  53. if e:
  54. m, e = m + 2**52, e - 1
  55. e -= 1074
  56. # add 0.5 ulps
  57. m, e = 2*m + 1, e - 1
  58. # convert to a decimal string
  59. if e >= 0:
  60. digits = m << e
  61. exponent = 0
  62. else:
  63. # m * 2**e = (m * 5**-e) * 10**e
  64. digits = m * 5**-e
  65. exponent = e
  66. s = '{}e{}'.format(digits, exponent)
  67. yield s
  68. def test_boundaries():
  69. # boundaries expressed as triples (n, e, u), where
  70. # n*10**e is an approximation to the boundary value and
  71. # u*10**e is 1ulp
  72. boundaries = [
  73. (10000000000000000000, -19, 1110), # a power of 2 boundary (1.0)
  74. (17976931348623159077, 289, 1995), # overflow boundary (2.**1024)
  75. (22250738585072013831, -327, 4941), # normal/subnormal (2.**-1022)
  76. (0, -327, 4941), # zero
  77. ]
  78. for n, e, u in boundaries:
  79. for j in range(1000):
  80. for i in range(TEST_SIZE):
  81. digits = n + random.randrange(-3*u, 3*u)
  82. exponent = e
  83. s = '{}e{}'.format(digits, exponent)
  84. yield s
  85. n *= 10
  86. u *= 10
  87. e -= 1
  88. def test_underflow_boundary():
  89. # test values close to 2**-1075, the underflow boundary; similar
  90. # to boundary_tests, except that the random error doesn't scale
  91. # with n
  92. for exponent in range(-400, -320):
  93. base = 10**-exponent // 2**1075
  94. for j in range(TEST_SIZE):
  95. digits = base + random.randrange(-1000, 1000)
  96. s = '{}e{}'.format(digits, exponent)
  97. yield s
  98. def test_bigcomp():
  99. for ndigs in 5, 10, 14, 15, 16, 17, 18, 19, 20, 40, 41, 50:
  100. dig10 = 10**ndigs
  101. for i in range(100 * TEST_SIZE):
  102. digits = random.randrange(dig10)
  103. exponent = random.randrange(-400, 400)
  104. s = '{}e{}'.format(digits, exponent)
  105. yield s
  106. def test_parsing():
  107. # make '0' more likely to be chosen than other digits
  108. digits = '000000123456789'
  109. signs = ('+', '-', '')
  110. # put together random short valid strings
  111. # \d*[.\d*]?e
  112. for i in range(1000):
  113. for j in range(TEST_SIZE):
  114. s = random.choice(signs)
  115. intpart_len = random.randrange(5)
  116. s += ''.join(random.choice(digits) for _ in range(intpart_len))
  117. if random.choice([True, False]):
  118. s += '.'
  119. fracpart_len = random.randrange(5)
  120. s += ''.join(random.choice(digits)
  121. for _ in range(fracpart_len))
  122. else:
  123. fracpart_len = 0
  124. if random.choice([True, False]):
  125. s += random.choice(['e', 'E'])
  126. s += random.choice(signs)
  127. exponent_len = random.randrange(1, 4)
  128. s += ''.join(random.choice(digits)
  129. for _ in range(exponent_len))
  130. if intpart_len + fracpart_len:
  131. yield s
  132. test_particular = [
  133. # squares
  134. '1.00000000100000000025',
  135. '1.0000000000000000000000000100000000000000000000000' #...
  136. '00025',
  137. '1.0000000000000000000000000000000000000000000010000' #...
  138. '0000000000000000000000000000000000000000025',
  139. '1.0000000000000000000000000000000000000000000000000' #...
  140. '000001000000000000000000000000000000000000000000000' #...
  141. '000000000025',
  142. '0.99999999900000000025',
  143. '0.9999999999999999999999999999999999999999999999999' #...
  144. '999000000000000000000000000000000000000000000000000' #...
  145. '000025',
  146. '0.9999999999999999999999999999999999999999999999999' #...
  147. '999999999999999999999999999999999999999999999999999' #...
  148. '999999999999999999999999999999999999999990000000000' #...
  149. '000000000000000000000000000000000000000000000000000' #...
  150. '000000000000000000000000000000000000000000000000000' #...
  151. '0000000000000000000000000000025',
  152. '1.0000000000000000000000000000000000000000000000000' #...
  153. '000000000000000000000000000000000000000000000000000' #...
  154. '100000000000000000000000000000000000000000000000000' #...
  155. '000000000000000000000000000000000000000000000000001',
  156. '1.0000000000000000000000000000000000000000000000000' #...
  157. '000000000000000000000000000000000000000000000000000' #...
  158. '500000000000000000000000000000000000000000000000000' #...
  159. '000000000000000000000000000000000000000000000000005',
  160. '1.0000000000000000000000000000000000000000000000000' #...
  161. '000000000100000000000000000000000000000000000000000' #...
  162. '000000000000000000250000000000000002000000000000000' #...
  163. '000000000000000000000000000000000000000000010000000' #...
  164. '000000000000000000000000000000000000000000000000000' #...
  165. '0000000000000000001',
  166. '1.0000000000000000000000000000000000000000000000000' #...
  167. '000000000100000000000000000000000000000000000000000' #...
  168. '000000000000000000249999999999999999999999999999999' #...
  169. '999999999999979999999999999999999999999999999999999' #...
  170. '999999999999999999999900000000000000000000000000000' #...
  171. '000000000000000000000000000000000000000000000000000' #...
  172. '00000000000000000000000001',
  173. '0.9999999999999999999999999999999999999999999999999' #...
  174. '999999999900000000000000000000000000000000000000000' #...
  175. '000000000000000000249999999999999998000000000000000' #...
  176. '000000000000000000000000000000000000000000010000000' #...
  177. '000000000000000000000000000000000000000000000000000' #...
  178. '0000000000000000001',
  179. '0.9999999999999999999999999999999999999999999999999' #...
  180. '999999999900000000000000000000000000000000000000000' #...
  181. '000000000000000000250000001999999999999999999999999' #...
  182. '999999999999999999999999999999999990000000000000000' #...
  183. '000000000000000000000000000000000000000000000000000' #...
  184. '1',
  185. # tough cases for ln etc.
  186. '1.000000000000000000000000000000000000000000000000' #...
  187. '00000000000000000000000000000000000000000000000000' #...
  188. '00100000000000000000000000000000000000000000000000' #...
  189. '00000000000000000000000000000000000000000000000000' #...
  190. '0001',
  191. '0.999999999999999999999999999999999999999999999999' #...
  192. '99999999999999999999999999999999999999999999999999' #...
  193. '99899999999999999999999999999999999999999999999999' #...
  194. '99999999999999999999999999999999999999999999999999' #...
  195. '99999999999999999999999999999999999999999999999999' #...
  196. '9999'
  197. ]
  198. TESTCASES = [
  199. [x for x in test_short_halfway_cases()],
  200. [x for x in test_halfway_cases()],
  201. [x for x in test_boundaries()],
  202. [x for x in test_underflow_boundary()],
  203. [x for x in test_bigcomp()],
  204. [x for x in test_parsing()],
  205. test_particular
  206. ]
  207. def un_randfloat():
  208. for i in range(1000):
  209. l = random.choice(TESTCASES[:6])
  210. yield random.choice(l)
  211. for v in test_particular:
  212. yield v
  213. def bin_randfloat():
  214. for i in range(1000):
  215. l1 = random.choice(TESTCASES)
  216. l2 = random.choice(TESTCASES)
  217. yield random.choice(l1), random.choice(l2)
  218. def tern_randfloat():
  219. for i in range(1000):
  220. l1 = random.choice(TESTCASES)
  221. l2 = random.choice(TESTCASES)
  222. l3 = random.choice(TESTCASES)
  223. yield random.choice(l1), random.choice(l2), random.choice(l3)