PageRenderTime 58ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/math/interp_math.py

https://bitbucket.org/dac_io/pypy
Python | 604 lines | 428 code | 58 blank | 118 comment | 109 complexity | c37546f094a8f5e1e92cd583a22eafa9 MD5 | raw file
  1. import math
  2. import sys
  3. from pypy.rlib import rfloat, unroll
  4. from pypy.interpreter.error import OperationError
  5. from pypy.interpreter.gateway import NoneNotWrapped
  6. class State:
  7. def __init__(self, space):
  8. self.w_e = space.wrap(math.e)
  9. self.w_pi = space.wrap(math.pi)
  10. def get(space):
  11. return space.fromcache(State)
  12. def _get_double(space, w_x):
  13. if space.is_w(space.type(w_x), space.w_float):
  14. return space.float_w(w_x)
  15. else:
  16. return space.float_w(space.float(w_x))
  17. def math1(space, f, w_x):
  18. x = _get_double(space, w_x)
  19. try:
  20. y = f(x)
  21. except OverflowError:
  22. raise OperationError(space.w_OverflowError,
  23. space.wrap("math range error"))
  24. except ValueError:
  25. raise OperationError(space.w_ValueError,
  26. space.wrap("math domain error"))
  27. return space.wrap(y)
  28. math1._annspecialcase_ = 'specialize:arg(1)'
  29. def math1_w(space, f, w_x):
  30. x = _get_double(space, w_x)
  31. try:
  32. r = f(x)
  33. except OverflowError:
  34. raise OperationError(space.w_OverflowError,
  35. space.wrap("math range error"))
  36. except ValueError:
  37. raise OperationError(space.w_ValueError,
  38. space.wrap("math domain error"))
  39. return r
  40. math1_w._annspecialcase_ = 'specialize:arg(1)'
  41. def math2(space, f, w_x, w_snd):
  42. x = _get_double(space, w_x)
  43. snd = _get_double(space, w_snd)
  44. try:
  45. r = f(x, snd)
  46. except OverflowError:
  47. raise OperationError(space.w_OverflowError,
  48. space.wrap("math range error"))
  49. except ValueError:
  50. raise OperationError(space.w_ValueError,
  51. space.wrap("math domain error"))
  52. return space.wrap(r)
  53. math2._annspecialcase_ = 'specialize:arg(1)'
  54. def trunc(space, w_x):
  55. """Truncate x."""
  56. return space.trunc(w_x)
  57. def copysign(space, w_x, w_y):
  58. """Return x with the sign of y."""
  59. # No exceptions possible.
  60. x = _get_double(space, w_x)
  61. y = _get_double(space, w_y)
  62. return space.wrap(rfloat.copysign(x, y))
  63. def isinf(space, w_x):
  64. """Return True if x is infinity."""
  65. return space.wrap(rfloat.isinf(_get_double(space, w_x)))
  66. def isnan(space, w_x):
  67. """Return True if x is not a number."""
  68. return space.wrap(rfloat.isnan(_get_double(space, w_x)))
  69. def pow(space, w_x, w_y):
  70. """pow(x,y)
  71. Return x**y (x to the power of y).
  72. """
  73. return math2(space, math.pow, w_x, w_y)
  74. def cosh(space, w_x):
  75. """cosh(x)
  76. Return the hyperbolic cosine of x.
  77. """
  78. return math1(space, math.cosh, w_x)
  79. def ldexp(space, w_x, w_i):
  80. """ldexp(x, i) -> x * (2**i)
  81. """
  82. x = _get_double(space, w_x)
  83. if (space.isinstance_w(w_i, space.w_int) or
  84. space.isinstance_w(w_i, space.w_long)):
  85. try:
  86. exp = space.int_w(w_i)
  87. except OperationError, e:
  88. if not e.match(space, space.w_OverflowError):
  89. raise
  90. if space.is_true(space.lt(w_i, space.wrap(0))):
  91. exp = -sys.maxint
  92. else:
  93. exp = sys.maxint
  94. else:
  95. raise OperationError(space.w_TypeError,
  96. space.wrap("integer required for second argument"))
  97. try:
  98. r = math.ldexp(x, exp)
  99. except OverflowError:
  100. raise OperationError(space.w_OverflowError,
  101. space.wrap("math range error"))
  102. except ValueError:
  103. raise OperationError(space.w_ValueError,
  104. space.wrap("math domain error"))
  105. return space.wrap(r)
  106. def hypot(space, w_x, w_y):
  107. """hypot(x,y)
  108. Return the Euclidean distance, sqrt(x*x + y*y).
  109. """
  110. return math2(space, math.hypot, w_x, w_y)
  111. def tan(space, w_x):
  112. """tan(x)
  113. Return the tangent of x (measured in radians).
  114. """
  115. return math1(space, math.tan, w_x)
  116. def asin(space, w_x):
  117. """asin(x)
  118. Return the arc sine (measured in radians) of x.
  119. """
  120. return math1(space, math.asin, w_x)
  121. def fabs(space, w_x):
  122. """fabs(x)
  123. Return the absolute value of the float x.
  124. """
  125. return math1(space, math.fabs, w_x)
  126. def floor(space, w_x):
  127. """floor(x)
  128. Return the floor of x as a float.
  129. This is the largest integral value <= x.
  130. """
  131. x = _get_double(space, w_x)
  132. return space.wrap(math.floor(x))
  133. def sqrt(space, w_x):
  134. """sqrt(x)
  135. Return the square root of x.
  136. """
  137. return math1(space, math.sqrt, w_x)
  138. def frexp(space, w_x):
  139. """frexp(x)
  140. Return the mantissa and exponent of x, as pair (m, e).
  141. m is a float and e is an int, such that x = m * 2.**e.
  142. If x is 0, m and e are both 0. Else 0.5 <= abs(m) < 1.0.
  143. """
  144. mant, expo = math1_w(space, math.frexp, w_x)
  145. return space.newtuple([space.wrap(mant), space.wrap(expo)])
  146. degToRad = math.pi / 180.0
  147. def degrees(space, w_x):
  148. """degrees(x) -> converts angle x from radians to degrees
  149. """
  150. return space.wrap(_get_double(space, w_x) / degToRad)
  151. def _log_any(space, w_x, base):
  152. # base is supposed to be positive or 0.0, which means we use e
  153. try:
  154. if space.is_true(space.isinstance(w_x, space.w_long)):
  155. # special case to support log(extremely-large-long)
  156. num = space.bigint_w(w_x)
  157. result = num.log(base)
  158. else:
  159. x = _get_double(space, w_x)
  160. if base == 10.0:
  161. result = math.log10(x)
  162. else:
  163. result = math.log(x)
  164. if base != 0.0:
  165. den = math.log(base)
  166. result /= den
  167. except OverflowError:
  168. raise OperationError(space.w_OverflowError,
  169. space.wrap('math range error'))
  170. except ValueError:
  171. raise OperationError(space.w_ValueError,
  172. space.wrap('math domain error'))
  173. return space.wrap(result)
  174. def log(space, w_x, w_base=NoneNotWrapped):
  175. """log(x[, base]) -> the logarithm of x to the given base.
  176. If the base not specified, returns the natural logarithm (base e) of x.
  177. """
  178. if w_base is None:
  179. base = 0.0
  180. else:
  181. base = _get_double(space, w_base)
  182. if base <= 0.0:
  183. # just for raising the proper errors
  184. return math1(space, math.log, w_base)
  185. return _log_any(space, w_x, base)
  186. def log10(space, w_x):
  187. """log10(x) -> the base 10 logarithm of x.
  188. """
  189. return _log_any(space, w_x, 10.0)
  190. def fmod(space, w_x, w_y):
  191. """fmod(x,y)
  192. Return fmod(x, y), according to platform C. x % y may differ.
  193. """
  194. return math2(space, math.fmod, w_x, w_y)
  195. def atan(space, w_x):
  196. """atan(x)
  197. Return the arc tangent (measured in radians) of x.
  198. """
  199. return math1(space, math.atan, w_x)
  200. def ceil(space, w_x):
  201. """ceil(x)
  202. Return the ceiling of x as a float.
  203. This is the smallest integral value >= x.
  204. """
  205. return math1(space, math.ceil, w_x)
  206. def sinh(space, w_x):
  207. """sinh(x)
  208. Return the hyperbolic sine of x.
  209. """
  210. return math1(space, math.sinh, w_x)
  211. def cos(space, w_x):
  212. """cos(x)
  213. Return the cosine of x (measured in radians).
  214. """
  215. return math1(space, math.cos, w_x)
  216. def tanh(space, w_x):
  217. """tanh(x)
  218. Return the hyperbolic tangent of x.
  219. """
  220. return math1(space, math.tanh, w_x)
  221. def radians(space, w_x):
  222. """radians(x) -> converts angle x from degrees to radians
  223. """
  224. return space.wrap(_get_double(space, w_x) * degToRad)
  225. def sin(space, w_x):
  226. """sin(x)
  227. Return the sine of x (measured in radians).
  228. """
  229. return math1(space, math.sin, w_x)
  230. def atan2(space, w_y, w_x):
  231. """atan2(y, x)
  232. Return the arc tangent (measured in radians) of y/x.
  233. Unlike atan(y/x), the signs of both x and y are considered.
  234. """
  235. return math2(space, math.atan2, w_y, w_x)
  236. def modf(space, w_x):
  237. """modf(x)
  238. Return the fractional and integer parts of x. Both results carry the sign
  239. of x. The integer part is returned as a real.
  240. """
  241. frac, intpart = math1_w(space, math.modf, w_x)
  242. return space.newtuple([space.wrap(frac), space.wrap(intpart)])
  243. def exp(space, w_x):
  244. """exp(x)
  245. Return e raised to the power of x.
  246. """
  247. return math1(space, math.exp, w_x)
  248. def acos(space, w_x):
  249. """acos(x)
  250. Return the arc cosine (measured in radians) of x.
  251. """
  252. return math1(space, math.acos, w_x)
  253. def fsum(space, w_iterable):
  254. """Sum an iterable of floats, trying to keep precision."""
  255. w_iter = space.iter(w_iterable)
  256. inf_sum = special_sum = 0.0
  257. partials = []
  258. while True:
  259. try:
  260. w_value = space.next(w_iter)
  261. except OperationError, e:
  262. if not e.match(space, space.w_StopIteration):
  263. raise
  264. break
  265. v = _get_double(space, w_value)
  266. original = v
  267. added = 0
  268. for y in partials:
  269. if abs(v) < abs(y):
  270. v, y = y, v
  271. hi = v + y
  272. yr = hi - v
  273. lo = y - yr
  274. if lo != 0.0:
  275. partials[added] = lo
  276. added += 1
  277. v = hi
  278. del partials[added:]
  279. if v != 0.0:
  280. if rfloat.isinf(v) or rfloat.isnan(v):
  281. if (not rfloat.isinf(original) and
  282. not rfloat.isnan(original)):
  283. raise OperationError(space.w_OverflowError,
  284. space.wrap("intermediate overflow"))
  285. if rfloat.isinf(original):
  286. inf_sum += original
  287. special_sum += original
  288. del partials[:]
  289. else:
  290. partials.append(v)
  291. if special_sum != 0.0:
  292. if rfloat.isnan(special_sum):
  293. raise OperationError(space.w_ValueError, space.wrap("-inf + inf"))
  294. return space.wrap(special_sum)
  295. hi = 0.0
  296. if partials:
  297. hi = partials[-1]
  298. j = 0
  299. lo = 0
  300. for j in range(len(partials) - 2, -1, -1):
  301. v = hi
  302. y = partials[j]
  303. assert abs(y) < abs(v)
  304. hi = v + y
  305. yr = hi - v
  306. lo = y - yr
  307. if lo != 0.0:
  308. break
  309. if j > 0 and (lo < 0.0 and partials[j - 1] < 0.0 or
  310. lo > 0.0 and partials[j - 1] > 0.0):
  311. y = lo * 2.0
  312. v = hi + y
  313. yr = v - hi
  314. if y == yr:
  315. hi = v
  316. return space.wrap(hi)
  317. def log1p(space, w_x):
  318. """Find log(x + 1)."""
  319. return math1(space, rfloat.log1p, w_x)
  320. def acosh(space, w_x):
  321. """Inverse hyperbolic cosine"""
  322. return math1(space, rfloat.acosh, w_x)
  323. def asinh(space, w_x):
  324. """Inverse hyperbolic sine"""
  325. return math1(space, rfloat.asinh, w_x)
  326. def atanh(space, w_x):
  327. """Inverse hyperbolic tangent"""
  328. return math1(space, rfloat.atanh, w_x)
  329. def expm1(space, w_x):
  330. """exp(x) - 1"""
  331. return math1(space, rfloat.expm1, w_x)
  332. def erf(space, w_x):
  333. """The error function"""
  334. return math1(space, _erf, w_x)
  335. def erfc(space, w_x):
  336. """The complementary error function"""
  337. return math1(space, _erfc, w_x)
  338. def gamma(space, w_x):
  339. """Compute the gamma function for x."""
  340. return math1(space, _gamma, w_x)
  341. def lgamma(space, w_x):
  342. """Compute the natural logarithm of the gamma function for x."""
  343. return math1(space, _lgamma, w_x)
  344. # Implementation of the error function, the complimentary error function, the
  345. # gamma function, and the natural log of the gamma function. These exist in
  346. # libm, but I hear those implementations are horrible.
  347. ERF_SERIES_CUTOFF = 1.5
  348. ERF_SERIES_TERMS = 25
  349. ERFC_CONTFRAC_CUTOFF = 30.
  350. ERFC_CONTFRAC_TERMS = 50
  351. _sqrtpi = 1.772453850905516027298167483341145182798
  352. def _erf_series(x):
  353. x2 = x * x
  354. acc = 0.
  355. fk = ERF_SERIES_TERMS + .5
  356. for i in range(ERF_SERIES_TERMS):
  357. acc = 2.0 + x2 * acc / fk
  358. fk -= 1.
  359. return acc * x * math.exp(-x2) / _sqrtpi
  360. def _erfc_contfrac(x):
  361. if x >= ERFC_CONTFRAC_CUTOFF:
  362. return 0.
  363. x2 = x * x
  364. a = 0.
  365. da = .5
  366. p = 1.
  367. p_last = 0.
  368. q = da + x2
  369. q_last = 1.
  370. for i in range(ERFC_CONTFRAC_TERMS):
  371. a += da
  372. da += 2.
  373. b = da + x2
  374. p_last, p = p, b * p - a * p_last
  375. q_last, q = q, b * q - a * q_last
  376. return p / q * x * math.exp(-x2) / _sqrtpi
  377. def _erf(x):
  378. if rfloat.isnan(x):
  379. return x
  380. absx = abs(x)
  381. if absx < ERF_SERIES_CUTOFF:
  382. return _erf_series(x)
  383. else:
  384. cf = _erfc_contfrac(absx)
  385. return 1. - cf if x > 0. else cf - 1.
  386. def _erfc(x):
  387. if rfloat.isnan(x):
  388. return x
  389. absx = abs(x)
  390. if absx < ERF_SERIES_CUTOFF:
  391. return 1. - _erf_series(x)
  392. else:
  393. cf = _erfc_contfrac(absx)
  394. return cf if x > 0. else 2. - cf
  395. def _sinpi(x):
  396. y = math.fmod(abs(x), 2.)
  397. n = int(rfloat.round_away(2. * y))
  398. if n == 0:
  399. r = math.sin(math.pi * y)
  400. elif n == 1:
  401. r = math.cos(math.pi * (y - .5))
  402. elif n == 2:
  403. r = math.sin(math.pi * (1. - y))
  404. elif n == 3:
  405. r = -math.cos(math.pi * (y - 1.5))
  406. elif n == 4:
  407. r = math.sin(math.pi * (y - 2.))
  408. else:
  409. raise AssertionError("should not reach")
  410. return rfloat.copysign(1., x) * r
  411. _lanczos_g = 6.024680040776729583740234375
  412. _lanczos_g_minus_half = 5.524680040776729583740234375
  413. _lanczos_num_coeffs = [
  414. 23531376880.410759688572007674451636754734846804940,
  415. 42919803642.649098768957899047001988850926355848959,
  416. 35711959237.355668049440185451547166705960488635843,
  417. 17921034426.037209699919755754458931112671403265390,
  418. 6039542586.3520280050642916443072979210699388420708,
  419. 1439720407.3117216736632230727949123939715485786772,
  420. 248874557.86205415651146038641322942321632125127801,
  421. 31426415.585400194380614231628318205362874684987640,
  422. 2876370.6289353724412254090516208496135991145378768,
  423. 186056.26539522349504029498971604569928220784236328,
  424. 8071.6720023658162106380029022722506138218516325024,
  425. 210.82427775157934587250973392071336271166969580291,
  426. 2.5066282746310002701649081771338373386264310793408
  427. ]
  428. _lanczos_den_coeffs = [
  429. 0.0, 39916800.0, 120543840.0, 150917976.0, 105258076.0, 45995730.0,
  430. 13339535.0, 2637558.0, 357423.0, 32670.0, 1925.0, 66.0, 1.0]
  431. LANCZOS_N = len(_lanczos_den_coeffs)
  432. _lanczos_n_iter = unroll.unrolling_iterable(range(LANCZOS_N))
  433. _lanczos_n_iter_back = unroll.unrolling_iterable(range(LANCZOS_N - 1, -1, -1))
  434. _gamma_integrals = [
  435. 1.0, 1.0, 2.0, 6.0, 24.0, 120.0, 720.0, 5040.0, 40320.0, 362880.0,
  436. 3628800.0, 39916800.0, 479001600.0, 6227020800.0, 87178291200.0,
  437. 1307674368000.0, 20922789888000.0, 355687428096000.0,
  438. 6402373705728000.0, 121645100408832000.0, 2432902008176640000.0,
  439. 51090942171709440000.0, 1124000727777607680000.0]
  440. def _lanczos_sum(x):
  441. num = 0.
  442. den = 0.
  443. assert x > 0.
  444. if x < 5.:
  445. for i in _lanczos_n_iter_back:
  446. num = num * x + _lanczos_num_coeffs[i]
  447. den = den * x + _lanczos_den_coeffs[i]
  448. else:
  449. for i in _lanczos_n_iter:
  450. num = num / x + _lanczos_num_coeffs[i]
  451. den = den / x + _lanczos_den_coeffs[i]
  452. return num / den
  453. def _gamma(x):
  454. if rfloat.isnan(x) or (rfloat.isinf(x) and x > 0.):
  455. return x
  456. if rfloat.isinf(x):
  457. raise ValueError("math domain error")
  458. if x == 0.:
  459. raise ValueError("math domain error")
  460. if x == math.floor(x):
  461. if x < 0.:
  462. raise ValueError("math domain error")
  463. if x < len(_gamma_integrals):
  464. return _gamma_integrals[int(x) - 1]
  465. absx = abs(x)
  466. if absx < 1e-20:
  467. r = 1. / x
  468. if rfloat.isinf(r):
  469. raise OverflowError("math range error")
  470. return r
  471. if absx > 200.:
  472. if x < 0.:
  473. return 0. / -_sinpi(x)
  474. else:
  475. raise OverflowError("math range error")
  476. y = absx + _lanczos_g_minus_half
  477. if absx > _lanczos_g_minus_half:
  478. q = y - absx
  479. z = q - _lanczos_g_minus_half
  480. else:
  481. q = y - _lanczos_g_minus_half
  482. z = q - absx
  483. z = z * _lanczos_g / y
  484. if x < 0.:
  485. r = -math.pi / _sinpi(absx) / absx * math.exp(y) / _lanczos_sum(absx)
  486. r -= z * r
  487. if absx < 140.:
  488. r /= math.pow(y, absx - .5)
  489. else:
  490. sqrtpow = math.pow(y, absx / 2. - .25)
  491. r /= sqrtpow
  492. r /= sqrtpow
  493. else:
  494. r = _lanczos_sum(absx) / math.exp(y)
  495. r += z * r
  496. if absx < 140.:
  497. r *= math.pow(y, absx - .5)
  498. else:
  499. sqrtpow = math.pow(y, absx / 2. - .25)
  500. r *= sqrtpow
  501. r *= sqrtpow
  502. if rfloat.isinf(r):
  503. raise OverflowError("math range error")
  504. return r
  505. def _lgamma(x):
  506. if rfloat.isnan(x):
  507. return x
  508. if rfloat.isinf(x):
  509. return rfloat.INFINITY
  510. if x == math.floor(x) and x <= 2.:
  511. if x <= 0.:
  512. raise ValueError("math range error")
  513. return 0.
  514. absx = abs(x)
  515. if absx < 1e-20:
  516. return -math.log(absx)
  517. if x > 0.:
  518. r = (math.log(_lanczos_sum(x)) - _lanczos_g + (x - .5) *
  519. (math.log(x + _lanczos_g - .5) - 1))
  520. else:
  521. r = (math.log(math.pi) - math.log(abs(_sinpi(absx))) - math.log(absx) -
  522. (math.log(_lanczos_sum(absx)) - _lanczos_g +
  523. (absx - .5) * (math.log(absx + _lanczos_g - .5) - 1)))
  524. if rfloat.isinf(r):
  525. raise OverflowError("math domain error")
  526. return r