PageRenderTime 64ms CodeModel.GetById 6ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/cmath/interp_cmath.py

https://bitbucket.org/dac_io/pypy
Python | 581 lines | 385 code | 84 blank | 112 comment | 142 complexity | ff400b86f0b3fd4ec3836be8aa550d4c MD5 | raw file
  1. import math
  2. from math import fabs
  3. from pypy.rlib.objectmodel import specialize
  4. from pypy.rlib.rfloat import copysign, asinh, log1p, isinf, isnan
  5. from pypy.tool.sourcetools import func_with_new_name
  6. from pypy.interpreter.error import OperationError
  7. from pypy.interpreter.gateway import NoneNotWrapped
  8. from pypy.module.cmath import names_and_docstrings
  9. from pypy.module.cmath.constant import DBL_MIN, CM_SCALE_UP, CM_SCALE_DOWN
  10. from pypy.module.cmath.constant import CM_LARGE_DOUBLE, DBL_MANT_DIG
  11. from pypy.module.cmath.constant import M_LN2, M_LN10
  12. from pypy.module.cmath.constant import CM_SQRT_LARGE_DOUBLE, CM_SQRT_DBL_MIN
  13. from pypy.module.cmath.constant import CM_LOG_LARGE_DOUBLE
  14. from pypy.module.cmath.special_value import isfinite, special_type, INF, NAN
  15. from pypy.module.cmath.special_value import sqrt_special_values
  16. from pypy.module.cmath.special_value import acos_special_values
  17. from pypy.module.cmath.special_value import acosh_special_values
  18. from pypy.module.cmath.special_value import asinh_special_values
  19. from pypy.module.cmath.special_value import atanh_special_values
  20. from pypy.module.cmath.special_value import log_special_values
  21. from pypy.module.cmath.special_value import exp_special_values
  22. from pypy.module.cmath.special_value import cosh_special_values
  23. from pypy.module.cmath.special_value import sinh_special_values
  24. from pypy.module.cmath.special_value import tanh_special_values
  25. from pypy.module.cmath.special_value import rect_special_values
  26. pi = math.pi
  27. e = math.e
  28. @specialize.arg(0)
  29. def call_c_func(c_func, space, x, y):
  30. try:
  31. result = c_func(x, y)
  32. except ValueError:
  33. raise OperationError(space.w_ValueError,
  34. space.wrap("math domain error"))
  35. except OverflowError:
  36. raise OperationError(space.w_OverflowError,
  37. space.wrap("math range error"))
  38. return result
  39. def unaryfn(c_func):
  40. def wrapper(space, w_z):
  41. x, y = space.unpackcomplex(w_z)
  42. resx, resy = call_c_func(c_func, space, x, y)
  43. return space.newcomplex(resx, resy)
  44. #
  45. name = c_func.func_name
  46. assert name.startswith('c_')
  47. wrapper.func_doc = names_and_docstrings[name[2:]]
  48. fnname = 'wrapped_' + name[2:]
  49. globals()[fnname] = func_with_new_name(wrapper, fnname)
  50. return c_func
  51. def c_neg(x, y):
  52. return (-x, -y)
  53. @unaryfn
  54. def c_sqrt(x, y):
  55. # Method: use symmetries to reduce to the case when x = z.real and y
  56. # = z.imag are nonnegative. Then the real part of the result is
  57. # given by
  58. #
  59. # s = sqrt((x + hypot(x, y))/2)
  60. #
  61. # and the imaginary part is
  62. #
  63. # d = (y/2)/s
  64. #
  65. # If either x or y is very large then there's a risk of overflow in
  66. # computation of the expression x + hypot(x, y). We can avoid this
  67. # by rewriting the formula for s as:
  68. #
  69. # s = 2*sqrt(x/8 + hypot(x/8, y/8))
  70. #
  71. # This costs us two extra multiplications/divisions, but avoids the
  72. # overhead of checking for x and y large.
  73. #
  74. # If both x and y are subnormal then hypot(x, y) may also be
  75. # subnormal, so will lack full precision. We solve this by rescaling
  76. # x and y by a sufficiently large power of 2 to ensure that x and y
  77. # are normal.
  78. if not isfinite(x) or not isfinite(y):
  79. return sqrt_special_values[special_type(x)][special_type(y)]
  80. if x == 0. and y == 0.:
  81. return (0., y)
  82. ax = fabs(x)
  83. ay = fabs(y)
  84. if ax < DBL_MIN and ay < DBL_MIN and (ax > 0. or ay > 0.):
  85. # here we catch cases where hypot(ax, ay) is subnormal
  86. ax = math.ldexp(ax, CM_SCALE_UP)
  87. ay1= math.ldexp(ay, CM_SCALE_UP)
  88. s = math.ldexp(math.sqrt(ax + math.hypot(ax, ay1)),
  89. CM_SCALE_DOWN)
  90. else:
  91. ax /= 8.
  92. s = 2.*math.sqrt(ax + math.hypot(ax, ay/8.))
  93. d = ay/(2.*s)
  94. if x >= 0.:
  95. return (s, copysign(d, y))
  96. else:
  97. return (d, copysign(s, y))
  98. @unaryfn
  99. def c_acos(x, y):
  100. if not isfinite(x) or not isfinite(y):
  101. return acos_special_values[special_type(x)][special_type(y)]
  102. if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE:
  103. # avoid unnecessary overflow for large arguments
  104. real = math.atan2(fabs(y), x)
  105. # split into cases to make sure that the branch cut has the
  106. # correct continuity on systems with unsigned zeros
  107. if x < 0.:
  108. imag = -copysign(math.log(math.hypot(x/2., y/2.)) +
  109. M_LN2*2., y)
  110. else:
  111. imag = copysign(math.log(math.hypot(x/2., y/2.)) +
  112. M_LN2*2., -y)
  113. else:
  114. s1x, s1y = c_sqrt(1.-x, -y)
  115. s2x, s2y = c_sqrt(1.+x, y)
  116. real = 2.*math.atan2(s1x, s2x)
  117. imag = asinh(s2x*s1y - s2y*s1x)
  118. return (real, imag)
  119. @unaryfn
  120. def c_acosh(x, y):
  121. # XXX the following two lines seem unnecessary at least on Linux;
  122. # the tests pass fine without them
  123. if not isfinite(x) or not isfinite(y):
  124. return acosh_special_values[special_type(x)][special_type(y)]
  125. if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE:
  126. # avoid unnecessary overflow for large arguments
  127. real = math.log(math.hypot(x/2., y/2.)) + M_LN2*2.
  128. imag = math.atan2(y, x)
  129. else:
  130. s1x, s1y = c_sqrt(x - 1., y)
  131. s2x, s2y = c_sqrt(x + 1., y)
  132. real = asinh(s1x*s2x + s1y*s2y)
  133. imag = 2.*math.atan2(s1y, s2x)
  134. return (real, imag)
  135. @unaryfn
  136. def c_asin(x, y):
  137. # asin(z) = -i asinh(iz)
  138. sx, sy = c_asinh(-y, x)
  139. return (sy, -sx)
  140. @unaryfn
  141. def c_asinh(x, y):
  142. if not isfinite(x) or not isfinite(y):
  143. return asinh_special_values[special_type(x)][special_type(y)]
  144. if fabs(x) > CM_LARGE_DOUBLE or fabs(y) > CM_LARGE_DOUBLE:
  145. if y >= 0.:
  146. real = copysign(math.log(math.hypot(x/2., y/2.)) +
  147. M_LN2*2., x)
  148. else:
  149. real = -copysign(math.log(math.hypot(x/2., y/2.)) +
  150. M_LN2*2., -x)
  151. imag = math.atan2(y, fabs(x))
  152. else:
  153. s1x, s1y = c_sqrt(1.+y, -x)
  154. s2x, s2y = c_sqrt(1.-y, x)
  155. real = asinh(s1x*s2y - s2x*s1y)
  156. imag = math.atan2(y, s1x*s2x - s1y*s2y)
  157. return (real, imag)
  158. @unaryfn
  159. def c_atan(x, y):
  160. # atan(z) = -i atanh(iz)
  161. sx, sy = c_atanh(-y, x)
  162. return (sy, -sx)
  163. @unaryfn
  164. def c_atanh(x, y):
  165. if not isfinite(x) or not isfinite(y):
  166. return atanh_special_values[special_type(x)][special_type(y)]
  167. # Reduce to case where x >= 0., using atanh(z) = -atanh(-z).
  168. if x < 0.:
  169. return c_neg(*c_atanh(*c_neg(x, y)))
  170. ay = fabs(y)
  171. if x > CM_SQRT_LARGE_DOUBLE or ay > CM_SQRT_LARGE_DOUBLE:
  172. # if abs(z) is large then we use the approximation
  173. # atanh(z) ~ 1/z +/- i*pi/2 (+/- depending on the sign
  174. # of y
  175. h = math.hypot(x/2., y/2.) # safe from overflow
  176. real = x/4./h/h
  177. # the two negations in the next line cancel each other out
  178. # except when working with unsigned zeros: they're there to
  179. # ensure that the branch cut has the correct continuity on
  180. # systems that don't support signed zeros
  181. imag = -copysign(math.pi/2., -y)
  182. elif x == 1. and ay < CM_SQRT_DBL_MIN:
  183. # C99 standard says: atanh(1+/-0.) should be inf +/- 0i
  184. if ay == 0.:
  185. raise ValueError("math domain error")
  186. #real = INF
  187. #imag = y
  188. else:
  189. real = -math.log(math.sqrt(ay)/math.sqrt(math.hypot(ay, 2.)))
  190. imag = copysign(math.atan2(2., -ay) / 2, y)
  191. else:
  192. real = log1p(4.*x/((1-x)*(1-x) + ay*ay))/4.
  193. imag = -math.atan2(-2.*y, (1-x)*(1+x) - ay*ay) / 2.
  194. return (real, imag)
  195. @unaryfn
  196. def c_log(x, y):
  197. # The usual formula for the real part is log(hypot(z.real, z.imag)).
  198. # There are four situations where this formula is potentially
  199. # problematic:
  200. #
  201. # (1) the absolute value of z is subnormal. Then hypot is subnormal,
  202. # so has fewer than the usual number of bits of accuracy, hence may
  203. # have large relative error. This then gives a large absolute error
  204. # in the log. This can be solved by rescaling z by a suitable power
  205. # of 2.
  206. #
  207. # (2) the absolute value of z is greater than DBL_MAX (e.g. when both
  208. # z.real and z.imag are within a factor of 1/sqrt(2) of DBL_MAX)
  209. # Again, rescaling solves this.
  210. #
  211. # (3) the absolute value of z is close to 1. In this case it's
  212. # difficult to achieve good accuracy, at least in part because a
  213. # change of 1ulp in the real or imaginary part of z can result in a
  214. # change of billions of ulps in the correctly rounded answer.
  215. #
  216. # (4) z = 0. The simplest thing to do here is to call the
  217. # floating-point log with an argument of 0, and let its behaviour
  218. # (returning -infinity, signaling a floating-point exception, setting
  219. # errno, or whatever) determine that of c_log. So the usual formula
  220. # is fine here.
  221. # XXX the following two lines seem unnecessary at least on Linux;
  222. # the tests pass fine without them
  223. if not isfinite(x) or not isfinite(y):
  224. return log_special_values[special_type(x)][special_type(y)]
  225. ax = fabs(x)
  226. ay = fabs(y)
  227. if ax > CM_LARGE_DOUBLE or ay > CM_LARGE_DOUBLE:
  228. real = math.log(math.hypot(ax/2., ay/2.)) + M_LN2
  229. elif ax < DBL_MIN and ay < DBL_MIN:
  230. if ax > 0. or ay > 0.:
  231. # catch cases where hypot(ax, ay) is subnormal
  232. real = math.log(math.hypot(math.ldexp(ax, DBL_MANT_DIG),
  233. math.ldexp(ay, DBL_MANT_DIG)))
  234. real -= DBL_MANT_DIG*M_LN2
  235. else:
  236. # log(+/-0. +/- 0i)
  237. raise ValueError("math domain error")
  238. #real = -INF
  239. #imag = atan2(y, x)
  240. else:
  241. h = math.hypot(ax, ay)
  242. if 0.71 <= h and h <= 1.73:
  243. am = max(ax, ay)
  244. an = min(ax, ay)
  245. real = log1p((am-1)*(am+1) + an*an) / 2.
  246. else:
  247. real = math.log(h)
  248. imag = math.atan2(y, x)
  249. return (real, imag)
  250. _inner_wrapped_log = wrapped_log
  251. def wrapped_log(space, w_z, w_base=NoneNotWrapped):
  252. w_logz = _inner_wrapped_log(space, w_z)
  253. if w_base is not None:
  254. w_logbase = _inner_wrapped_log(space, w_base)
  255. return space.truediv(w_logz, w_logbase)
  256. else:
  257. return w_logz
  258. wrapped_log.func_doc = _inner_wrapped_log.func_doc
  259. @unaryfn
  260. def c_log10(x, y):
  261. rx, ry = c_log(x, y)
  262. return (rx / M_LN10, ry / M_LN10)
  263. @unaryfn
  264. def c_exp(x, y):
  265. if not isfinite(x) or not isfinite(y):
  266. if isinf(x) and isfinite(y) and y != 0.:
  267. if x > 0:
  268. real = copysign(INF, math.cos(y))
  269. imag = copysign(INF, math.sin(y))
  270. else:
  271. real = copysign(0., math.cos(y))
  272. imag = copysign(0., math.sin(y))
  273. r = (real, imag)
  274. else:
  275. r = exp_special_values[special_type(x)][special_type(y)]
  276. # need to raise ValueError if y is +/- infinity and x is not
  277. # a NaN and not -infinity
  278. if isinf(y) and (isfinite(x) or (isinf(x) and x > 0)):
  279. raise ValueError("math domain error")
  280. return r
  281. if x > CM_LOG_LARGE_DOUBLE:
  282. l = math.exp(x-1.)
  283. real = l * math.cos(y) * math.e
  284. imag = l * math.sin(y) * math.e
  285. else:
  286. l = math.exp(x)
  287. real = l * math.cos(y)
  288. imag = l * math.sin(y)
  289. if isinf(real) or isinf(imag):
  290. raise OverflowError("math range error")
  291. return real, imag
  292. @unaryfn
  293. def c_cosh(x, y):
  294. if not isfinite(x) or not isfinite(y):
  295. if isinf(x) and isfinite(y) and y != 0.:
  296. if x > 0:
  297. real = copysign(INF, math.cos(y))
  298. imag = copysign(INF, math.sin(y))
  299. else:
  300. real = copysign(INF, math.cos(y))
  301. imag = -copysign(INF, math.sin(y))
  302. r = (real, imag)
  303. else:
  304. r = cosh_special_values[special_type(x)][special_type(y)]
  305. # need to raise ValueError if y is +/- infinity and x is not
  306. # a NaN
  307. if isinf(y) and not isnan(x):
  308. raise ValueError("math domain error")
  309. return r
  310. if fabs(x) > CM_LOG_LARGE_DOUBLE:
  311. # deal correctly with cases where cosh(x) overflows but
  312. # cosh(z) does not.
  313. x_minus_one = x - copysign(1., x)
  314. real = math.cos(y) * math.cosh(x_minus_one) * math.e
  315. imag = math.sin(y) * math.sinh(x_minus_one) * math.e
  316. else:
  317. real = math.cos(y) * math.cosh(x)
  318. imag = math.sin(y) * math.sinh(x)
  319. if isinf(real) or isinf(imag):
  320. raise OverflowError("math range error")
  321. return real, imag
  322. @unaryfn
  323. def c_sinh(x, y):
  324. # special treatment for sinh(+/-inf + iy) if y is finite and nonzero
  325. if not isfinite(x) or not isfinite(y):
  326. if isinf(x) and isfinite(y) and y != 0.:
  327. if x > 0:
  328. real = copysign(INF, math.cos(y))
  329. imag = copysign(INF, math.sin(y))
  330. else:
  331. real = -copysign(INF, math.cos(y))
  332. imag = copysign(INF, math.sin(y))
  333. r = (real, imag)
  334. else:
  335. r = sinh_special_values[special_type(x)][special_type(y)]
  336. # need to raise ValueError if y is +/- infinity and x is not
  337. # a NaN
  338. if isinf(y) and not isnan(x):
  339. raise ValueError("math domain error")
  340. return r
  341. if fabs(x) > CM_LOG_LARGE_DOUBLE:
  342. x_minus_one = x - copysign(1., x)
  343. real = math.cos(y) * math.sinh(x_minus_one) * math.e
  344. imag = math.sin(y) * math.cosh(x_minus_one) * math.e
  345. else:
  346. real = math.cos(y) * math.sinh(x)
  347. imag = math.sin(y) * math.cosh(x)
  348. if isinf(real) or isinf(imag):
  349. raise OverflowError("math range error")
  350. return real, imag
  351. @unaryfn
  352. def c_tanh(x, y):
  353. # Formula:
  354. #
  355. # tanh(x+iy) = (tanh(x)(1+tan(y)^2) + i tan(y)(1-tanh(x))^2) /
  356. # (1+tan(y)^2 tanh(x)^2)
  357. #
  358. # To avoid excessive roundoff error, 1-tanh(x)^2 is better computed
  359. # as 1/cosh(x)^2. When abs(x) is large, we approximate 1-tanh(x)^2
  360. # by 4 exp(-2*x) instead, to avoid possible overflow in the
  361. # computation of cosh(x).
  362. if not isfinite(x) or not isfinite(y):
  363. if isinf(x) and isfinite(y) and y != 0.:
  364. if x > 0:
  365. real = 1.0 # vv XXX why is the 2. there?
  366. imag = copysign(0., 2. * math.sin(y) * math.cos(y))
  367. else:
  368. real = -1.0
  369. imag = copysign(0., 2. * math.sin(y) * math.cos(y))
  370. r = (real, imag)
  371. else:
  372. r = tanh_special_values[special_type(x)][special_type(y)]
  373. # need to raise ValueError if y is +/-infinity and x is finite
  374. if isinf(y) and isfinite(x):
  375. raise ValueError("math domain error")
  376. return r
  377. if fabs(x) > CM_LOG_LARGE_DOUBLE:
  378. real = copysign(1., x)
  379. imag = 4. * math.sin(y) * math.cos(y) * math.exp(-2.*fabs(x))
  380. else:
  381. tx = math.tanh(x)
  382. ty = math.tan(y)
  383. cx = 1. / math.cosh(x)
  384. txty = tx * ty
  385. denom = 1. + txty * txty
  386. real = tx * (1. + ty*ty) / denom
  387. imag = ((ty / denom) * cx) * cx
  388. return real, imag
  389. @unaryfn
  390. def c_cos(x, y):
  391. # cos(z) = cosh(iz)
  392. return c_cosh(-y, x)
  393. @unaryfn
  394. def c_sin(x, y):
  395. # sin(z) = -i sinh(iz)
  396. sx, sy = c_sinh(-y, x)
  397. return sy, -sx
  398. @unaryfn
  399. def c_tan(x, y):
  400. # tan(z) = -i tanh(iz)
  401. sx, sy = c_tanh(-y, x)
  402. return sy, -sx
  403. def c_rect(r, phi):
  404. if not isfinite(r) or not isfinite(phi):
  405. # if r is +/-infinity and phi is finite but nonzero then
  406. # result is (+-INF +-INF i), but we need to compute cos(phi)
  407. # and sin(phi) to figure out the signs.
  408. if isinf(r) and isfinite(phi) and phi != 0.:
  409. if r > 0:
  410. real = copysign(INF, math.cos(phi))
  411. imag = copysign(INF, math.sin(phi))
  412. else:
  413. real = -copysign(INF, math.cos(phi))
  414. imag = -copysign(INF, math.sin(phi))
  415. z = (real, imag)
  416. else:
  417. z = rect_special_values[special_type(r)][special_type(phi)]
  418. # need to raise ValueError if r is a nonzero number and phi
  419. # is infinite
  420. if r != 0. and not isnan(r) and isinf(phi):
  421. raise ValueError("math domain error")
  422. return z
  423. real = r * math.cos(phi)
  424. imag = r * math.sin(phi)
  425. return real, imag
  426. def wrapped_rect(space, w_x, w_y):
  427. x = space.float_w(w_x)
  428. y = space.float_w(w_y)
  429. resx, resy = call_c_func(c_rect, space, x, y)
  430. return space.newcomplex(resx, resy)
  431. wrapped_rect.func_doc = names_and_docstrings['rect']
  432. def c_phase(x, y):
  433. # Windows screws up atan2 for inf and nan, and alpha Tru64 5.1 doesn't
  434. # follow C99 for atan2(0., 0.).
  435. if isnan(x) or isnan(y):
  436. return NAN
  437. if isinf(y):
  438. if isinf(x):
  439. if copysign(1., x) == 1.:
  440. # atan2(+-inf, +inf) == +-pi/4
  441. return copysign(0.25 * math.pi, y)
  442. else:
  443. # atan2(+-inf, -inf) == +-pi*3/4
  444. return copysign(0.75 * math.pi, y)
  445. # atan2(+-inf, x) == +-pi/2 for finite x
  446. return copysign(0.5 * math.pi, y)
  447. if isinf(x) or y == 0.:
  448. if copysign(1., x) == 1.:
  449. # atan2(+-y, +inf) = atan2(+-0, +x) = +-0.
  450. return copysign(0., y)
  451. else:
  452. # atan2(+-y, -inf) = atan2(+-0., -x) = +-pi.
  453. return copysign(math.pi, y)
  454. return math.atan2(y, x)
  455. def wrapped_phase(space, w_z):
  456. x, y = space.unpackcomplex(w_z)
  457. result = call_c_func(c_phase, space, x, y)
  458. return space.newfloat(result)
  459. wrapped_phase.func_doc = names_and_docstrings['phase']
  460. def c_abs(x, y):
  461. if not isfinite(x) or not isfinite(y):
  462. # C99 rules: if either the real or the imaginary part is an
  463. # infinity, return infinity, even if the other part is a NaN.
  464. if isinf(x):
  465. return INF
  466. if isinf(y):
  467. return INF
  468. # either the real or imaginary part is a NaN,
  469. # and neither is infinite. Result should be NaN.
  470. return NAN
  471. result = math.hypot(x, y)
  472. if not isfinite(result):
  473. raise OverflowError("math range error")
  474. return result
  475. def c_polar(x, y):
  476. phi = c_phase(x, y)
  477. r = c_abs(x, y)
  478. return r, phi
  479. def wrapped_polar(space, w_z):
  480. x, y = space.unpackcomplex(w_z)
  481. resx, resy = call_c_func(c_polar, space, x, y)
  482. return space.newtuple([space.newfloat(resx), space.newfloat(resy)])
  483. wrapped_polar.func_doc = names_and_docstrings['polar']
  484. def c_isinf(x, y):
  485. return isinf(x) or isinf(y)
  486. def wrapped_isinf(space, w_z):
  487. x, y = space.unpackcomplex(w_z)
  488. res = c_isinf(x, y)
  489. return space.newbool(res)
  490. wrapped_isinf.func_doc = names_and_docstrings['isinf']
  491. def c_isnan(x, y):
  492. return isnan(x) or isnan(y)
  493. def wrapped_isnan(space, w_z):
  494. x, y = space.unpackcomplex(w_z)
  495. res = c_isnan(x, y)
  496. return space.newbool(res)
  497. wrapped_isnan.func_doc = names_and_docstrings['isnan']