930_deterministic_float.py 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. import math
  2. import pkpy
  3. config = pkpy.configmacros
  4. if config["PK_ENABLE_DETERMINISM"] == 0:
  5. exit(0)
  6. def assertEqual(a, b):
  7. if a == b:
  8. return
  9. print(f'{a} != {b} ({a-b})')
  10. raise AssertionError
  11. # test constants
  12. assertEqual(math.pi, 3.14159265358979323846)
  13. assertEqual(math.e, 2.7182818284590452354)
  14. assert math.inf, math.inf
  15. assert math.nan != math.nan
  16. # test ceil
  17. assert math.ceil(math.pi) == 4
  18. assert math.ceil(-math.e) == -2
  19. # test floor
  20. assert math.floor(math.pi) == 3
  21. assert math.floor(-math.e) == -3
  22. # test trunc
  23. assert math.trunc(-math.e) == -2
  24. assert math.trunc(3.999) == 3
  25. # test fabs
  26. assertEqual(math.fabs(math.pi), 3.14159265358979323846)
  27. assertEqual(math.fabs(-math.pi), 3.14159265358979323846)
  28. # test gcd
  29. assertEqual(math.gcd(10, 5), 5)
  30. assertEqual(math.gcd(10, 6), 2)
  31. assertEqual(math.gcd(10, 7), 1)
  32. assertEqual(math.gcd(10, 10), 10)
  33. assertEqual(math.gcd(-10, 10), 10)
  34. # test isfinite, isinf, isnan
  35. assertEqual(math.isfinite(math.pi), True)
  36. assertEqual(math.isfinite(math.inf), False)
  37. assertEqual(math.isfinite(math.nan), False)
  38. assertEqual(math.isinf(math.pi), False)
  39. assertEqual(math.isinf(math.inf), True)
  40. assertEqual(math.isinf(math.nan), False)
  41. assertEqual(math.isnan(math.pi), False)
  42. assertEqual(math.isnan(math.inf), False)
  43. assertEqual(math.isnan(math.nan), True)
  44. # test exp
  45. assertEqual(math.exp(0), 1.0)
  46. assertEqual(math.exp(1), math.e)
  47. assertEqual(math.exp(1.5), 4.48168907033806362960604019463)
  48. assertEqual(math.exp(3), 20.0855369231876608182574273087)
  49. assertEqual(math.exp(-3), 0.04978706836786396527916309651)
  50. assertEqual(math.exp(-2.253647), 0.1050155336754953 - 1.387778780781446e-17)
  51. assertEqual(math.exp(4.729036), 113.186398052200445363268954679)
  52. # test log series
  53. assertEqual(math.log(0), -math.inf)
  54. assertEqual(math.log(1), 0.0)
  55. assertEqual(math.log(2), 0.69314718055994530942)
  56. assertEqual(math.log(math.e), 1.0)
  57. assertEqual(math.log(10), 2.30258509299404545700440394284)
  58. assertEqual(math.log(28.897124), 3.363742074595449)
  59. assertEqual(math.log2(math.e), 1.4426950408889634074)
  60. assertEqual(math.log2(78.781291), 6.299781153677818)
  61. assertEqual(math.log10(math.e), 0.43429448190325182765)
  62. assertEqual(math.log10(56.907822), 1.755171964426069 + 4.440892098500626e-16)
  63. # test pow
  64. assertEqual(math.pow(2,2), 4.0)
  65. assertEqual(math.pow(1.41421356237309504880, 2), 2.0 + 4.440892098500626e-16)
  66. assertEqual(math.pow(0.70710678118654752440, 2), 0.5000000000000001)
  67. assertEqual(math.pow(-1.255782,-3), -0.5049603042167915)
  68. assertEqual(math.pow(6.127042, 4.071529), 1604.40754645674428502388764172)
  69. # test sqrt
  70. # these match CPython bit-for-bit (hardware sqrt is correctly rounded, see dmath_sqrt)
  71. assertEqual(math.sqrt(2), 1.4142135623730951)
  72. assertEqual(math.sqrt(math.pi), 1.7724538509055159)
  73. assertEqual(math.sqrt(125.872509), 11.21929182257062)
  74. assertEqual(math.sqrt(1225.296280), 35.00423231553579)
  75. assertEqual(math.sqrt(0.1), 0.31622776601683794)
  76. assertEqual(math.sqrt(1e300), 1e150)
  77. assertEqual(math.sqrt(1.7976931348623157e308), 1.3407807929942596e154)
  78. # subnormal inputs
  79. assertEqual(math.sqrt(1e-320), 9.99994433575849e-161)
  80. assertEqual(math.sqrt(5e-324), 2.2227587494850775e-162)
  81. # perfect squares must be exact, the old exp/log based sqrt gave sqrt(9) == 2.9999999999999996
  82. for i in range(2000):
  83. assertEqual(math.sqrt(i * i), float(i))
  84. # special values
  85. assertEqual(math.sqrt(math.inf), math.inf)
  86. assertEqual(math.copysign(1.0, math.sqrt(0.0)), 1.0)
  87. assertEqual(math.copysign(1.0, math.sqrt(-0.0)), -1.0)
  88. assert math.isnan(math.sqrt(-1))
  89. assert math.isnan(math.sqrt(-math.inf))
  90. assert math.isnan(math.sqrt(math.nan))
  91. # test cbrt
  92. # cbrt is not required by IEEE 754 to be correctly rounded, so unlike sqrt there is
  93. # no hardware instruction to lean on; these come from the musl port in dmath_zig.c.
  94. # The cases marked below differ from CPython's math.cbrt by 1 ulp on Windows, where
  95. # it is the musl port that is correctly rounded and the platform CRT that is not.
  96. assertEqual(math.cbrt(2), 1.2599210498948732) # CPython/msvc gives 1.259921049894873
  97. assertEqual(math.cbrt(3), 1.4422495703074083)
  98. assertEqual(math.cbrt(10), 2.154434690031884)
  99. assertEqual(math.cbrt(0.1), 0.4641588833612779) # CPython/msvc gives 0.464158883361278
  100. assertEqual(math.cbrt(125.872509), 5.011606490362725)
  101. assertEqual(math.cbrt(1225.296280), 10.700737364388822)
  102. assertEqual(math.cbrt(1e300), 1e100)
  103. assertEqual(math.cbrt(1.7976931348623157e308), 5.643803094122362e102)
  104. # negative inputs, which the old dmath_pow based cbrt returned nan for
  105. assertEqual(math.cbrt(-8.0), -2.0)
  106. assertEqual(math.cbrt(-0.5), -0.7937005259840998) # CPython/msvc gives -0.7937005259840997
  107. assertEqual(math.cbrt(-1000.0), -10.0)
  108. assertEqual(math.cbrt(-1e300), -1e100)
  109. # subnormal inputs, which the old cbrt got wrong by orders of magnitude
  110. # because dmath_log2 does not normalize them: cbrt(5e-324) came out as 2.2323972485981933e-103
  111. assertEqual(math.cbrt(5e-324), 1.7031839360032603e-108)
  112. assertEqual(math.cbrt(-5e-324), -1.7031839360032603e-108)
  113. assertEqual(math.cbrt(1e-320), 2.1544266950262728e-107) # CPython/msvc gives 2.154426695026273e-107
  114. assertEqual(math.cbrt(2.2250738585072014e-308), 2.812644285236262e-103) # CPython/msvc gives 2.8126442852362615e-103
  115. # perfect cubes must be exact; the old cbrt got 1800 of these 2000 wrong,
  116. # e.g. cbrt(27) == 2.9999999999999996 and cbrt(8) == 1.9999999999999998
  117. for i in range(2000):
  118. assertEqual(math.cbrt(i * i * i), float(i))
  119. assertEqual(math.cbrt(-(i * i * i)), -float(i))
  120. # special values
  121. assertEqual(math.cbrt(math.inf), math.inf)
  122. assertEqual(math.cbrt(-math.inf), -math.inf)
  123. assertEqual(math.copysign(1.0, math.cbrt(0.0)), 1.0)
  124. assertEqual(math.copysign(1.0, math.cbrt(-0.0)), -1.0)
  125. assert math.isnan(math.cbrt(math.nan))
  126. # test cos, sin, tan
  127. assertEqual(math.cos(0), 1.0)
  128. assertEqual(math.cos(math.pi/2), 6.123233995736766e-17)
  129. assertEqual(math.cos(math.pi), -1.0)
  130. assertEqual(math.cos(-11.352808), 0.3496839289707818 - 5.551115123125783e-17)
  131. assertEqual(math.cos(7.294708), 0.530570640518482)
  132. assertEqual(math.sin(0), 0.0)
  133. assertEqual(math.sin(math.pi/2), 1.0)
  134. assertEqual(math.sin(math.pi), 1.224646799147353e-16 + 2.465190328815662e-32)
  135. assertEqual(math.sin(-2.837592), -0.2993398018896187)
  136. assertEqual(math.sin(9.294782), 0.1296301374714747)
  137. assertEqual(math.tan(0), 0.0)
  138. assertEqual(math.tan(math.pi/2), 1.633123935319537e+16)
  139. assertEqual(math.tan(math.pi), -1.224646799147353e-16 - 2.465190328815662e-32)
  140. assertEqual(math.tan(-4.812975), 9.908188146466314)
  141. assertEqual(math.tan(1.875814), -3.176189742032396 - 4.440892098500626e-16)
  142. # test acos, asin, atan
  143. # these match CPython bit-for-bit (ported from Zig, see src/common/dmath_zig.c)
  144. assertEqual(math.acos(0), 1.5707963267948966)
  145. assertEqual(math.acos(1), 0.0)
  146. assertEqual(math.acos(-0.758293), 2.4314869951218965)
  147. assertEqual(math.acos(0.024758), 1.546035796825635)
  148. assertEqual(math.asin(0), 0.0)
  149. assertEqual(math.asin(1), 1.5707963267948966)
  150. assertEqual(math.asin(-0.225895), -0.22786168657739128)
  151. assertEqual(math.asin(0.955658), 1.2718861958194234)
  152. assertEqual(math.atan(0), 0.0)
  153. assertEqual(math.atan(1), 0.7853981633974483)
  154. assertEqual(math.atan(-3.758927), -1.3107852846106174)
  155. assertEqual(math.atan(35.789293), 1.542862277280122)
  156. # test atan2
  157. assertEqual(math.atan2(math.pi/4, math.pi/4), 0.7853981633974483)
  158. assertEqual(math.atan2(-math.pi/4, math.pi/4), -0.7853981633974483)
  159. assertEqual(math.atan2(-math.pi/4, -math.pi/4), -2.356194490192345)
  160. assertEqual(math.atan2(math.pi/4, -math.pi/4), 2.356194490192345)
  161. assertEqual(math.atan2(1.573823, 0.685329), 1.160103682924653)
  162. assertEqual(math.atan2(-0.899663, 0.668972), -0.9314162757114095)
  163. assertEqual(math.atan2(-0.762894, -0.126497), -1.7351133471732965)
  164. assertEqual(math.atan2(0.468463, -0.992734), 2.7006834106923736)
  165. # near-vertical vectors used to hit a NaN in the old atan (ratio >= 2^26),
  166. # which silently turned into direction index 0 for callers
  167. assertEqual(math.atan2(1.0, 1e-8), 1.5707963167948966)
  168. assertEqual(math.atan2(1.0, 1e-12), 1.5707963267938967)
  169. assertEqual(math.atan2(-3.5, 1e-15), -1.5707963267948963)
  170. # test fsum, sum
  171. fsum_sin = math.fsum([math.sin(i) for i in range(5000)])
  172. fsum_cos = math.fsum([math.cos(i) for i in range(5000, 9999)])
  173. assertEqual(fsum_sin, 1.267667771014267 + 2.220446049250313e-16)
  174. assertEqual(fsum_cos, 1.949547793618193 - 4.440892098500626e-16)
  175. assertEqual(fsum_sin + fsum_cos, 3.21721556463246)
  176. sum_sin = sum([math.sin(i) for i in range(5000)])
  177. sum_cos = sum([math.cos(i) for i in range(5000, 9999)])
  178. assertEqual(sum_sin, 1.267667771014264 - 2.220446049250313e-16)
  179. assertEqual(sum_cos, 1.949547793618197 - 4.440892098500626e-16)
  180. assertEqual(sum_sin + sum_cos, 3.21721556463246 + 4.440892098500626e-16)
  181. # test fmod
  182. assertEqual(math.fmod(-2.0, 3.0), -2.0)
  183. assertEqual(math.fmod(2.0, 3.0), 2.0)
  184. assertEqual(math.fmod(4.0, 3.0), 1.0)
  185. assertEqual(math.fmod(-4.0, 3.0), -1.0)
  186. # test modf
  187. x, y = math.modf(math.pi)
  188. assertEqual(x, 0.14159265358979323846 - 1.110223024625157e-16)
  189. assertEqual(y, 3.0)
  190. x, y = math.modf(-math.e)
  191. assertEqual(x, -0.7182818284590451)
  192. assertEqual(y, -2.0)
  193. # test factorial
  194. assertEqual(math.factorial(0), 1)
  195. assertEqual(math.factorial(1), 1)
  196. assertEqual(math.factorial(2), 2)
  197. assertEqual(math.factorial(3), 6)
  198. assertEqual(math.factorial(4), 24)
  199. assertEqual(math.factorial(5), 120)