图片解析应用
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.

935 lines
27 KiB

  1. """
  2. Computational functions for interval arithmetic.
  3. """
  4. from .backend import xrange
  5. from .libmpf import (
  6. ComplexResult,
  7. round_down, round_up, round_floor, round_ceiling, round_nearest,
  8. prec_to_dps, repr_dps, dps_to_prec,
  9. bitcount,
  10. from_float,
  11. fnan, finf, fninf, fzero, fhalf, fone, fnone,
  12. mpf_sign, mpf_lt, mpf_le, mpf_gt, mpf_ge, mpf_eq, mpf_cmp,
  13. mpf_min_max,
  14. mpf_floor, from_int, to_int, to_str, from_str,
  15. mpf_abs, mpf_neg, mpf_pos, mpf_add, mpf_sub, mpf_mul, mpf_mul_int,
  16. mpf_div, mpf_shift, mpf_pow_int,
  17. from_man_exp, MPZ_ONE)
  18. from .libelefun import (
  19. mpf_log, mpf_exp, mpf_sqrt, mpf_atan, mpf_atan2,
  20. mpf_pi, mod_pi2, mpf_cos_sin
  21. )
  22. from .gammazeta import mpf_gamma, mpf_rgamma, mpf_loggamma, mpc_loggamma
  23. def mpi_str(s, prec):
  24. sa, sb = s
  25. dps = prec_to_dps(prec) + 5
  26. return "[%s, %s]" % (to_str(sa, dps), to_str(sb, dps))
  27. #dps = prec_to_dps(prec)
  28. #m = mpi_mid(s, prec)
  29. #d = mpf_shift(mpi_delta(s, 20), -1)
  30. #return "%s +/- %s" % (to_str(m, dps), to_str(d, 3))
  31. mpi_zero = (fzero, fzero)
  32. mpi_one = (fone, fone)
  33. def mpi_eq(s, t):
  34. return s == t
  35. def mpi_ne(s, t):
  36. return s != t
  37. def mpi_lt(s, t):
  38. sa, sb = s
  39. ta, tb = t
  40. if mpf_lt(sb, ta): return True
  41. if mpf_ge(sa, tb): return False
  42. return None
  43. def mpi_le(s, t):
  44. sa, sb = s
  45. ta, tb = t
  46. if mpf_le(sb, ta): return True
  47. if mpf_gt(sa, tb): return False
  48. return None
  49. def mpi_gt(s, t): return mpi_lt(t, s)
  50. def mpi_ge(s, t): return mpi_le(t, s)
  51. def mpi_add(s, t, prec=0):
  52. sa, sb = s
  53. ta, tb = t
  54. a = mpf_add(sa, ta, prec, round_floor)
  55. b = mpf_add(sb, tb, prec, round_ceiling)
  56. if a == fnan: a = fninf
  57. if b == fnan: b = finf
  58. return a, b
  59. def mpi_sub(s, t, prec=0):
  60. sa, sb = s
  61. ta, tb = t
  62. a = mpf_sub(sa, tb, prec, round_floor)
  63. b = mpf_sub(sb, ta, prec, round_ceiling)
  64. if a == fnan: a = fninf
  65. if b == fnan: b = finf
  66. return a, b
  67. def mpi_delta(s, prec):
  68. sa, sb = s
  69. return mpf_sub(sb, sa, prec, round_up)
  70. def mpi_mid(s, prec):
  71. sa, sb = s
  72. return mpf_shift(mpf_add(sa, sb, prec, round_nearest), -1)
  73. def mpi_pos(s, prec):
  74. sa, sb = s
  75. a = mpf_pos(sa, prec, round_floor)
  76. b = mpf_pos(sb, prec, round_ceiling)
  77. return a, b
  78. def mpi_neg(s, prec=0):
  79. sa, sb = s
  80. a = mpf_neg(sb, prec, round_floor)
  81. b = mpf_neg(sa, prec, round_ceiling)
  82. return a, b
  83. def mpi_abs(s, prec=0):
  84. sa, sb = s
  85. sas = mpf_sign(sa)
  86. sbs = mpf_sign(sb)
  87. # Both points nonnegative?
  88. if sas >= 0:
  89. a = mpf_pos(sa, prec, round_floor)
  90. b = mpf_pos(sb, prec, round_ceiling)
  91. # Upper point nonnegative?
  92. elif sbs >= 0:
  93. a = fzero
  94. negsa = mpf_neg(sa)
  95. if mpf_lt(negsa, sb):
  96. b = mpf_pos(sb, prec, round_ceiling)
  97. else:
  98. b = mpf_pos(negsa, prec, round_ceiling)
  99. # Both negative?
  100. else:
  101. a = mpf_neg(sb, prec, round_floor)
  102. b = mpf_neg(sa, prec, round_ceiling)
  103. return a, b
  104. # TODO: optimize
  105. def mpi_mul_mpf(s, t, prec):
  106. return mpi_mul(s, (t, t), prec)
  107. def mpi_div_mpf(s, t, prec):
  108. return mpi_div(s, (t, t), prec)
  109. def mpi_mul(s, t, prec=0):
  110. sa, sb = s
  111. ta, tb = t
  112. sas = mpf_sign(sa)
  113. sbs = mpf_sign(sb)
  114. tas = mpf_sign(ta)
  115. tbs = mpf_sign(tb)
  116. if sas == sbs == 0:
  117. # Should maybe be undefined
  118. if ta == fninf or tb == finf:
  119. return fninf, finf
  120. return fzero, fzero
  121. if tas == tbs == 0:
  122. # Should maybe be undefined
  123. if sa == fninf or sb == finf:
  124. return fninf, finf
  125. return fzero, fzero
  126. if sas >= 0:
  127. # positive * positive
  128. if tas >= 0:
  129. a = mpf_mul(sa, ta, prec, round_floor)
  130. b = mpf_mul(sb, tb, prec, round_ceiling)
  131. if a == fnan: a = fzero
  132. if b == fnan: b = finf
  133. # positive * negative
  134. elif tbs <= 0:
  135. a = mpf_mul(sb, ta, prec, round_floor)
  136. b = mpf_mul(sa, tb, prec, round_ceiling)
  137. if a == fnan: a = fninf
  138. if b == fnan: b = fzero
  139. # positive * both signs
  140. else:
  141. a = mpf_mul(sb, ta, prec, round_floor)
  142. b = mpf_mul(sb, tb, prec, round_ceiling)
  143. if a == fnan: a = fninf
  144. if b == fnan: b = finf
  145. elif sbs <= 0:
  146. # negative * positive
  147. if tas >= 0:
  148. a = mpf_mul(sa, tb, prec, round_floor)
  149. b = mpf_mul(sb, ta, prec, round_ceiling)
  150. if a == fnan: a = fninf
  151. if b == fnan: b = fzero
  152. # negative * negative
  153. elif tbs <= 0:
  154. a = mpf_mul(sb, tb, prec, round_floor)
  155. b = mpf_mul(sa, ta, prec, round_ceiling)
  156. if a == fnan: a = fzero
  157. if b == fnan: b = finf
  158. # negative * both signs
  159. else:
  160. a = mpf_mul(sa, tb, prec, round_floor)
  161. b = mpf_mul(sa, ta, prec, round_ceiling)
  162. if a == fnan: a = fninf
  163. if b == fnan: b = finf
  164. else:
  165. # General case: perform all cross-multiplications and compare
  166. # Since the multiplications can be done exactly, we need only
  167. # do 4 (instead of 8: two for each rounding mode)
  168. cases = [mpf_mul(sa, ta), mpf_mul(sa, tb), mpf_mul(sb, ta), mpf_mul(sb, tb)]
  169. if fnan in cases:
  170. a, b = (fninf, finf)
  171. else:
  172. a, b = mpf_min_max(cases)
  173. a = mpf_pos(a, prec, round_floor)
  174. b = mpf_pos(b, prec, round_ceiling)
  175. return a, b
  176. def mpi_square(s, prec=0):
  177. sa, sb = s
  178. if mpf_ge(sa, fzero):
  179. a = mpf_mul(sa, sa, prec, round_floor)
  180. b = mpf_mul(sb, sb, prec, round_ceiling)
  181. elif mpf_le(sb, fzero):
  182. a = mpf_mul(sb, sb, prec, round_floor)
  183. b = mpf_mul(sa, sa, prec, round_ceiling)
  184. else:
  185. sa = mpf_neg(sa)
  186. sa, sb = mpf_min_max([sa, sb])
  187. a = fzero
  188. b = mpf_mul(sb, sb, prec, round_ceiling)
  189. return a, b
  190. def mpi_div(s, t, prec):
  191. sa, sb = s
  192. ta, tb = t
  193. sas = mpf_sign(sa)
  194. sbs = mpf_sign(sb)
  195. tas = mpf_sign(ta)
  196. tbs = mpf_sign(tb)
  197. # 0 / X
  198. if sas == sbs == 0:
  199. # 0 / <interval containing 0>
  200. if (tas < 0 and tbs > 0) or (tas == 0 or tbs == 0):
  201. return fninf, finf
  202. return fzero, fzero
  203. # Denominator contains both negative and positive numbers;
  204. # this should properly be a multi-interval, but the closest
  205. # match is the entire (extended) real line
  206. if tas < 0 and tbs > 0:
  207. return fninf, finf
  208. # Assume denominator to be nonnegative
  209. if tas < 0:
  210. return mpi_div(mpi_neg(s), mpi_neg(t), prec)
  211. # Division by zero
  212. # XXX: make sure all results make sense
  213. if tas == 0:
  214. # Numerator contains both signs?
  215. if sas < 0 and sbs > 0:
  216. return fninf, finf
  217. if tas == tbs:
  218. return fninf, finf
  219. # Numerator positive?
  220. if sas >= 0:
  221. a = mpf_div(sa, tb, prec, round_floor)
  222. b = finf
  223. if sbs <= 0:
  224. a = fninf
  225. b = mpf_div(sb, tb, prec, round_ceiling)
  226. # Division with positive denominator
  227. # We still have to handle nans resulting from inf/0 or inf/inf
  228. else:
  229. # Nonnegative numerator
  230. if sas >= 0:
  231. a = mpf_div(sa, tb, prec, round_floor)
  232. b = mpf_div(sb, ta, prec, round_ceiling)
  233. if a == fnan: a = fzero
  234. if b == fnan: b = finf
  235. # Nonpositive numerator
  236. elif sbs <= 0:
  237. a = mpf_div(sa, ta, prec, round_floor)
  238. b = mpf_div(sb, tb, prec, round_ceiling)
  239. if a == fnan: a = fninf
  240. if b == fnan: b = fzero
  241. # Numerator contains both signs?
  242. else:
  243. a = mpf_div(sa, ta, prec, round_floor)
  244. b = mpf_div(sb, ta, prec, round_ceiling)
  245. if a == fnan: a = fninf
  246. if b == fnan: b = finf
  247. return a, b
  248. def mpi_pi(prec):
  249. a = mpf_pi(prec, round_floor)
  250. b = mpf_pi(prec, round_ceiling)
  251. return a, b
  252. def mpi_exp(s, prec):
  253. sa, sb = s
  254. # exp is monotonic
  255. a = mpf_exp(sa, prec, round_floor)
  256. b = mpf_exp(sb, prec, round_ceiling)
  257. return a, b
  258. def mpi_log(s, prec):
  259. sa, sb = s
  260. # log is monotonic
  261. a = mpf_log(sa, prec, round_floor)
  262. b = mpf_log(sb, prec, round_ceiling)
  263. return a, b
  264. def mpi_sqrt(s, prec):
  265. sa, sb = s
  266. # sqrt is monotonic
  267. a = mpf_sqrt(sa, prec, round_floor)
  268. b = mpf_sqrt(sb, prec, round_ceiling)
  269. return a, b
  270. def mpi_atan(s, prec):
  271. sa, sb = s
  272. a = mpf_atan(sa, prec, round_floor)
  273. b = mpf_atan(sb, prec, round_ceiling)
  274. return a, b
  275. def mpi_pow_int(s, n, prec):
  276. sa, sb = s
  277. if n < 0:
  278. return mpi_div((fone, fone), mpi_pow_int(s, -n, prec+20), prec)
  279. if n == 0:
  280. return (fone, fone)
  281. if n == 1:
  282. return s
  283. if n == 2:
  284. return mpi_square(s, prec)
  285. # Odd -- signs are preserved
  286. if n & 1:
  287. a = mpf_pow_int(sa, n, prec, round_floor)
  288. b = mpf_pow_int(sb, n, prec, round_ceiling)
  289. # Even -- important to ensure positivity
  290. else:
  291. sas = mpf_sign(sa)
  292. sbs = mpf_sign(sb)
  293. # Nonnegative?
  294. if sas >= 0:
  295. a = mpf_pow_int(sa, n, prec, round_floor)
  296. b = mpf_pow_int(sb, n, prec, round_ceiling)
  297. # Nonpositive?
  298. elif sbs <= 0:
  299. a = mpf_pow_int(sb, n, prec, round_floor)
  300. b = mpf_pow_int(sa, n, prec, round_ceiling)
  301. # Mixed signs?
  302. else:
  303. a = fzero
  304. # max(-a,b)**n
  305. sa = mpf_neg(sa)
  306. if mpf_ge(sa, sb):
  307. b = mpf_pow_int(sa, n, prec, round_ceiling)
  308. else:
  309. b = mpf_pow_int(sb, n, prec, round_ceiling)
  310. return a, b
  311. def mpi_pow(s, t, prec):
  312. ta, tb = t
  313. if ta == tb and ta not in (finf, fninf):
  314. if ta == from_int(to_int(ta)):
  315. return mpi_pow_int(s, to_int(ta), prec)
  316. if ta == fhalf:
  317. return mpi_sqrt(s, prec)
  318. u = mpi_log(s, prec + 20)
  319. v = mpi_mul(u, t, prec + 20)
  320. return mpi_exp(v, prec)
  321. def MIN(x, y):
  322. if mpf_le(x, y):
  323. return x
  324. return y
  325. def MAX(x, y):
  326. if mpf_ge(x, y):
  327. return x
  328. return y
  329. def cos_sin_quadrant(x, wp):
  330. sign, man, exp, bc = x
  331. if x == fzero:
  332. return fone, fzero, 0
  333. # TODO: combine evaluation code to avoid duplicate modulo
  334. c, s = mpf_cos_sin(x, wp)
  335. t, n, wp_ = mod_pi2(man, exp, exp+bc, 15)
  336. if sign:
  337. n = -1-n
  338. return c, s, n
  339. def mpi_cos_sin(x, prec):
  340. a, b = x
  341. if a == b == fzero:
  342. return (fone, fone), (fzero, fzero)
  343. # Guaranteed to contain both -1 and 1
  344. if (finf in x) or (fninf in x):
  345. return (fnone, fone), (fnone, fone)
  346. wp = prec + 20
  347. ca, sa, na = cos_sin_quadrant(a, wp)
  348. cb, sb, nb = cos_sin_quadrant(b, wp)
  349. ca, cb = mpf_min_max([ca, cb])
  350. sa, sb = mpf_min_max([sa, sb])
  351. # Both functions are monotonic within one quadrant
  352. if na == nb:
  353. pass
  354. # Guaranteed to contain both -1 and 1
  355. elif nb - na >= 4:
  356. return (fnone, fone), (fnone, fone)
  357. else:
  358. # cos has maximum between a and b
  359. if na//4 != nb//4:
  360. cb = fone
  361. # cos has minimum
  362. if (na-2)//4 != (nb-2)//4:
  363. ca = fnone
  364. # sin has maximum
  365. if (na-1)//4 != (nb-1)//4:
  366. sb = fone
  367. # sin has minimum
  368. if (na-3)//4 != (nb-3)//4:
  369. sa = fnone
  370. # Perturb to force interval rounding
  371. more = from_man_exp((MPZ_ONE<<wp) + (MPZ_ONE<<10), -wp)
  372. less = from_man_exp((MPZ_ONE<<wp) - (MPZ_ONE<<10), -wp)
  373. def finalize(v, rounding):
  374. if bool(v[0]) == (rounding == round_floor):
  375. p = more
  376. else:
  377. p = less
  378. v = mpf_mul(v, p, prec, rounding)
  379. sign, man, exp, bc = v
  380. if exp+bc >= 1:
  381. if sign:
  382. return fnone
  383. return fone
  384. return v
  385. ca = finalize(ca, round_floor)
  386. cb = finalize(cb, round_ceiling)
  387. sa = finalize(sa, round_floor)
  388. sb = finalize(sb, round_ceiling)
  389. return (ca,cb), (sa,sb)
  390. def mpi_cos(x, prec):
  391. return mpi_cos_sin(x, prec)[0]
  392. def mpi_sin(x, prec):
  393. return mpi_cos_sin(x, prec)[1]
  394. def mpi_tan(x, prec):
  395. cos, sin = mpi_cos_sin(x, prec+20)
  396. return mpi_div(sin, cos, prec)
  397. def mpi_cot(x, prec):
  398. cos, sin = mpi_cos_sin(x, prec+20)
  399. return mpi_div(cos, sin, prec)
  400. def mpi_from_str_a_b(x, y, percent, prec):
  401. wp = prec + 20
  402. xa = from_str(x, wp, round_floor)
  403. xb = from_str(x, wp, round_ceiling)
  404. #ya = from_str(y, wp, round_floor)
  405. y = from_str(y, wp, round_ceiling)
  406. assert mpf_ge(y, fzero)
  407. if percent:
  408. y = mpf_mul(MAX(mpf_abs(xa), mpf_abs(xb)), y, wp, round_ceiling)
  409. y = mpf_div(y, from_int(100), wp, round_ceiling)
  410. a = mpf_sub(xa, y, prec, round_floor)
  411. b = mpf_add(xb, y, prec, round_ceiling)
  412. return a, b
  413. def mpi_from_str(s, prec):
  414. """
  415. Parse an interval number given as a string.
  416. Allowed forms are
  417. "-1.23e-27"
  418. Any single decimal floating-point literal.
  419. "a +- b" or "a (b)"
  420. a is the midpoint of the interval and b is the half-width
  421. "a +- b%" or "a (b%)"
  422. a is the midpoint of the interval and the half-width
  423. is b percent of a (`a \times b / 100`).
  424. "[a, b]"
  425. The interval indicated directly.
  426. "x[y,z]e"
  427. x are shared digits, y and z are unequal digits, e is the exponent.
  428. """
  429. e = ValueError("Improperly formed interval number '%s'" % s)
  430. s = s.replace(" ", "")
  431. wp = prec + 20
  432. if "+-" in s:
  433. x, y = s.split("+-")
  434. return mpi_from_str_a_b(x, y, False, prec)
  435. # case 2
  436. elif "(" in s:
  437. # Don't confuse with a complex number (x,y)
  438. if s[0] == "(" or ")" not in s:
  439. raise e
  440. s = s.replace(")", "")
  441. percent = False
  442. if "%" in s:
  443. if s[-1] != "%":
  444. raise e
  445. percent = True
  446. s = s.replace("%", "")
  447. x, y = s.split("(")
  448. return mpi_from_str_a_b(x, y, percent, prec)
  449. elif "," in s:
  450. if ('[' not in s) or (']' not in s):
  451. raise e
  452. if s[0] == '[':
  453. # case 3
  454. s = s.replace("[", "")
  455. s = s.replace("]", "")
  456. a, b = s.split(",")
  457. a = from_str(a, prec, round_floor)
  458. b = from_str(b, prec, round_ceiling)
  459. return a, b
  460. else:
  461. # case 4
  462. x, y = s.split('[')
  463. y, z = y.split(',')
  464. if 'e' in s:
  465. z, e = z.split(']')
  466. else:
  467. z, e = z.rstrip(']'), ''
  468. a = from_str(x+y+e, prec, round_floor)
  469. b = from_str(x+z+e, prec, round_ceiling)
  470. return a, b
  471. else:
  472. a = from_str(s, prec, round_floor)
  473. b = from_str(s, prec, round_ceiling)
  474. return a, b
  475. def mpi_to_str(x, dps, use_spaces=True, brackets='[]', mode='brackets', error_dps=4, **kwargs):
  476. """
  477. Convert a mpi interval to a string.
  478. **Arguments**
  479. *dps*
  480. decimal places to use for printing
  481. *use_spaces*
  482. use spaces for more readable output, defaults to true
  483. *brackets*
  484. pair of strings (or two-character string) giving left and right brackets
  485. *mode*
  486. mode of display: 'plusminus', 'percent', 'brackets' (default) or 'diff'
  487. *error_dps*
  488. limit the error to *error_dps* digits (mode 'plusminus and 'percent')
  489. Additional keyword arguments are forwarded to the mpf-to-string conversion
  490. for the components of the output.
  491. **Examples**
  492. >>> from mpmath import mpi, mp
  493. >>> mp.dps = 30
  494. >>> x = mpi(1, 2)._mpi_
  495. >>> mpi_to_str(x, 2, mode='plusminus')
  496. '1.5 +- 0.5'
  497. >>> mpi_to_str(x, 2, mode='percent')
  498. '1.5 (33.33%)'
  499. >>> mpi_to_str(x, 2, mode='brackets')
  500. '[1.0, 2.0]'
  501. >>> mpi_to_str(x, 2, mode='brackets' , brackets=('<', '>'))
  502. '<1.0, 2.0>'
  503. >>> x = mpi('5.2582327113062393041', '5.2582327113062749951')._mpi_
  504. >>> mpi_to_str(x, 15, mode='diff')
  505. '5.2582327113062[4, 7]'
  506. >>> mpi_to_str(mpi(0)._mpi_, 2, mode='percent')
  507. '0.0 (0.0%)'
  508. """
  509. prec = dps_to_prec(dps)
  510. wp = prec + 20
  511. a, b = x
  512. mid = mpi_mid(x, prec)
  513. delta = mpi_delta(x, prec)
  514. a_str = to_str(a, dps, **kwargs)
  515. b_str = to_str(b, dps, **kwargs)
  516. mid_str = to_str(mid, dps, **kwargs)
  517. sp = ""
  518. if use_spaces:
  519. sp = " "
  520. br1, br2 = brackets
  521. if mode == 'plusminus':
  522. delta_str = to_str(mpf_shift(delta,-1), dps, **kwargs)
  523. s = mid_str + sp + "+-" + sp + delta_str
  524. elif mode == 'percent':
  525. if mid == fzero:
  526. p = fzero
  527. else:
  528. # p = 100 * delta(x) / (2*mid(x))
  529. p = mpf_mul(delta, from_int(100))
  530. p = mpf_div(p, mpf_mul(mid, from_int(2)), wp)
  531. s = mid_str + sp + "(" + to_str(p, error_dps) + "%)"
  532. elif mode == 'brackets':
  533. s = br1 + a_str + "," + sp + b_str + br2
  534. elif mode == 'diff':
  535. # use more digits if str(x.a) and str(x.b) are equal
  536. if a_str == b_str:
  537. a_str = to_str(a, dps+3, **kwargs)
  538. b_str = to_str(b, dps+3, **kwargs)
  539. # separate mantissa and exponent
  540. a = a_str.split('e')
  541. if len(a) == 1:
  542. a.append('')
  543. b = b_str.split('e')
  544. if len(b) == 1:
  545. b.append('')
  546. if a[1] == b[1]:
  547. if a[0] != b[0]:
  548. for i in xrange(len(a[0]) + 1):
  549. if a[0][i] != b[0][i]:
  550. break
  551. s = (a[0][:i] + br1 + a[0][i:] + ',' + sp + b[0][i:] + br2
  552. + 'e'*min(len(a[1]), 1) + a[1])
  553. else: # no difference
  554. s = a[0] + br1 + br2 + 'e'*min(len(a[1]), 1) + a[1]
  555. else:
  556. s = br1 + 'e'.join(a) + ',' + sp + 'e'.join(b) + br2
  557. else:
  558. raise ValueError("'%s' is unknown mode for printing mpi" % mode)
  559. return s
  560. def mpci_add(x, y, prec):
  561. a, b = x
  562. c, d = y
  563. return mpi_add(a, c, prec), mpi_add(b, d, prec)
  564. def mpci_sub(x, y, prec):
  565. a, b = x
  566. c, d = y
  567. return mpi_sub(a, c, prec), mpi_sub(b, d, prec)
  568. def mpci_neg(x, prec=0):
  569. a, b = x
  570. return mpi_neg(a, prec), mpi_neg(b, prec)
  571. def mpci_pos(x, prec):
  572. a, b = x
  573. return mpi_pos(a, prec), mpi_pos(b, prec)
  574. def mpci_mul(x, y, prec):
  575. # TODO: optimize for real/imag cases
  576. a, b = x
  577. c, d = y
  578. r1 = mpi_mul(a,c)
  579. r2 = mpi_mul(b,d)
  580. re = mpi_sub(r1,r2,prec)
  581. i1 = mpi_mul(a,d)
  582. i2 = mpi_mul(b,c)
  583. im = mpi_add(i1,i2,prec)
  584. return re, im
  585. def mpci_div(x, y, prec):
  586. # TODO: optimize for real/imag cases
  587. a, b = x
  588. c, d = y
  589. wp = prec+20
  590. m1 = mpi_square(c)
  591. m2 = mpi_square(d)
  592. m = mpi_add(m1,m2,wp)
  593. re = mpi_add(mpi_mul(a,c), mpi_mul(b,d), wp)
  594. im = mpi_sub(mpi_mul(b,c), mpi_mul(a,d), wp)
  595. re = mpi_div(re, m, prec)
  596. im = mpi_div(im, m, prec)
  597. return re, im
  598. def mpci_exp(x, prec):
  599. a, b = x
  600. wp = prec+20
  601. r = mpi_exp(a, wp)
  602. c, s = mpi_cos_sin(b, wp)
  603. a = mpi_mul(r, c, prec)
  604. b = mpi_mul(r, s, prec)
  605. return a, b
  606. def mpi_shift(x, n):
  607. a, b = x
  608. return mpf_shift(a,n), mpf_shift(b,n)
  609. def mpi_cosh_sinh(x, prec):
  610. # TODO: accuracy for small x
  611. wp = prec+20
  612. e1 = mpi_exp(x, wp)
  613. e2 = mpi_div(mpi_one, e1, wp)
  614. c = mpi_add(e1, e2, prec)
  615. s = mpi_sub(e1, e2, prec)
  616. c = mpi_shift(c, -1)
  617. s = mpi_shift(s, -1)
  618. return c, s
  619. def mpci_cos(x, prec):
  620. a, b = x
  621. wp = prec+10
  622. c, s = mpi_cos_sin(a, wp)
  623. ch, sh = mpi_cosh_sinh(b, wp)
  624. re = mpi_mul(c, ch, prec)
  625. im = mpi_mul(s, sh, prec)
  626. return re, mpi_neg(im)
  627. def mpci_sin(x, prec):
  628. a, b = x
  629. wp = prec+10
  630. c, s = mpi_cos_sin(a, wp)
  631. ch, sh = mpi_cosh_sinh(b, wp)
  632. re = mpi_mul(s, ch, prec)
  633. im = mpi_mul(c, sh, prec)
  634. return re, im
  635. def mpci_abs(x, prec):
  636. a, b = x
  637. if a == mpi_zero:
  638. return mpi_abs(b)
  639. if b == mpi_zero:
  640. return mpi_abs(a)
  641. # Important: nonnegative
  642. a = mpi_square(a)
  643. b = mpi_square(b)
  644. t = mpi_add(a, b, prec+20)
  645. return mpi_sqrt(t, prec)
  646. def mpi_atan2(y, x, prec):
  647. ya, yb = y
  648. xa, xb = x
  649. # Constrained to the real line
  650. if ya == yb == fzero:
  651. if mpf_ge(xa, fzero):
  652. return mpi_zero
  653. return mpi_pi(prec)
  654. # Right half-plane
  655. if mpf_ge(xa, fzero):
  656. if mpf_ge(ya, fzero):
  657. a = mpf_atan2(ya, xb, prec, round_floor)
  658. else:
  659. a = mpf_atan2(ya, xa, prec, round_floor)
  660. if mpf_ge(yb, fzero):
  661. b = mpf_atan2(yb, xa, prec, round_ceiling)
  662. else:
  663. b = mpf_atan2(yb, xb, prec, round_ceiling)
  664. # Upper half-plane
  665. elif mpf_ge(ya, fzero):
  666. b = mpf_atan2(ya, xa, prec, round_ceiling)
  667. if mpf_le(xb, fzero):
  668. a = mpf_atan2(yb, xb, prec, round_floor)
  669. else:
  670. a = mpf_atan2(ya, xb, prec, round_floor)
  671. # Lower half-plane
  672. elif mpf_le(yb, fzero):
  673. a = mpf_atan2(yb, xa, prec, round_floor)
  674. if mpf_le(xb, fzero):
  675. b = mpf_atan2(ya, xb, prec, round_ceiling)
  676. else:
  677. b = mpf_atan2(yb, xb, prec, round_ceiling)
  678. # Covering the origin
  679. else:
  680. b = mpf_pi(prec, round_ceiling)
  681. a = mpf_neg(b)
  682. return a, b
  683. def mpci_arg(z, prec):
  684. x, y = z
  685. return mpi_atan2(y, x, prec)
  686. def mpci_log(z, prec):
  687. x, y = z
  688. re = mpi_log(mpci_abs(z, prec+20), prec)
  689. im = mpci_arg(z, prec)
  690. return re, im
  691. def mpci_pow(x, y, prec):
  692. # TODO: recognize/speed up real cases, integer y
  693. yre, yim = y
  694. if yim == mpi_zero:
  695. ya, yb = yre
  696. if ya == yb:
  697. sign, man, exp, bc = yb
  698. if man and exp >= 0:
  699. return mpci_pow_int(x, (-1)**sign * int(man<<exp), prec)
  700. # x^0
  701. if yb == fzero:
  702. return mpci_pow_int(x, 0, prec)
  703. wp = prec+20
  704. return mpci_exp(mpci_mul(y, mpci_log(x, wp), wp), prec)
  705. def mpci_square(x, prec):
  706. a, b = x
  707. # (a+bi)^2 = (a^2-b^2) + 2abi
  708. re = mpi_sub(mpi_square(a), mpi_square(b), prec)
  709. im = mpi_mul(a, b, prec)
  710. im = mpi_shift(im, 1)
  711. return re, im
  712. def mpci_pow_int(x, n, prec):
  713. if n < 0:
  714. return mpci_div((mpi_one,mpi_zero), mpci_pow_int(x, -n, prec+20), prec)
  715. if n == 0:
  716. return mpi_one, mpi_zero
  717. if n == 1:
  718. return mpci_pos(x, prec)
  719. if n == 2:
  720. return mpci_square(x, prec)
  721. wp = prec + 20
  722. result = (mpi_one, mpi_zero)
  723. while n:
  724. if n & 1:
  725. result = mpci_mul(result, x, wp)
  726. n -= 1
  727. x = mpci_square(x, wp)
  728. n >>= 1
  729. return mpci_pos(result, prec)
  730. gamma_min_a = from_float(1.46163214496)
  731. gamma_min_b = from_float(1.46163214497)
  732. gamma_min = (gamma_min_a, gamma_min_b)
  733. gamma_mono_imag_a = from_float(-1.1)
  734. gamma_mono_imag_b = from_float(1.1)
  735. def mpi_overlap(x, y):
  736. a, b = x
  737. c, d = y
  738. if mpf_lt(d, a): return False
  739. if mpf_gt(c, b): return False
  740. return True
  741. # type = 0 -- gamma
  742. # type = 1 -- factorial
  743. # type = 2 -- 1/gamma
  744. # type = 3 -- log-gamma
  745. def mpi_gamma(z, prec, type=0):
  746. a, b = z
  747. wp = prec+20
  748. if type == 1:
  749. return mpi_gamma(mpi_add(z, mpi_one, wp), prec, 0)
  750. # increasing
  751. if mpf_gt(a, gamma_min_b):
  752. if type == 0:
  753. c = mpf_gamma(a, prec, round_floor)
  754. d = mpf_gamma(b, prec, round_ceiling)
  755. elif type == 2:
  756. c = mpf_rgamma(b, prec, round_floor)
  757. d = mpf_rgamma(a, prec, round_ceiling)
  758. elif type == 3:
  759. c = mpf_loggamma(a, prec, round_floor)
  760. d = mpf_loggamma(b, prec, round_ceiling)
  761. # decreasing
  762. elif mpf_gt(a, fzero) and mpf_lt(b, gamma_min_a):
  763. if type == 0:
  764. c = mpf_gamma(b, prec, round_floor)
  765. d = mpf_gamma(a, prec, round_ceiling)
  766. elif type == 2:
  767. c = mpf_rgamma(a, prec, round_floor)
  768. d = mpf_rgamma(b, prec, round_ceiling)
  769. elif type == 3:
  770. c = mpf_loggamma(b, prec, round_floor)
  771. d = mpf_loggamma(a, prec, round_ceiling)
  772. else:
  773. # TODO: reflection formula
  774. znew = mpi_add(z, mpi_one, wp)
  775. if type == 0: return mpi_div(mpi_gamma(znew, prec+2, 0), z, prec)
  776. if type == 2: return mpi_mul(mpi_gamma(znew, prec+2, 2), z, prec)
  777. if type == 3: return mpi_sub(mpi_gamma(znew, prec+2, 3), mpi_log(z, prec+2), prec)
  778. return c, d
  779. def mpci_gamma(z, prec, type=0):
  780. (a1,a2), (b1,b2) = z
  781. # Real case
  782. if b1 == b2 == fzero and (type != 3 or mpf_gt(a1,fzero)):
  783. return mpi_gamma(z, prec, type), mpi_zero
  784. # Estimate precision
  785. wp = prec+20
  786. if type != 3:
  787. amag = a2[2]+a2[3]
  788. bmag = b2[2]+b2[3]
  789. if a2 != fzero:
  790. mag = max(amag, bmag)
  791. else:
  792. mag = bmag
  793. an = abs(to_int(a2))
  794. bn = abs(to_int(b2))
  795. absn = max(an, bn)
  796. gamma_size = max(0,absn*mag)
  797. wp += bitcount(gamma_size)
  798. # Assume type != 1
  799. if type == 1:
  800. (a1,a2) = mpi_add((a1,a2), mpi_one, wp); z = (a1,a2), (b1,b2)
  801. type = 0
  802. # Avoid non-monotonic region near the negative real axis
  803. if mpf_lt(a1, gamma_min_b):
  804. if mpi_overlap((b1,b2), (gamma_mono_imag_a, gamma_mono_imag_b)):
  805. # TODO: reflection formula
  806. #if mpf_lt(a2, mpf_shift(fone,-1)):
  807. # znew = mpci_sub((mpi_one,mpi_zero),z,wp)
  808. # ...
  809. # Recurrence:
  810. # gamma(z) = gamma(z+1)/z
  811. znew = mpi_add((a1,a2), mpi_one, wp), (b1,b2)
  812. if type == 0: return mpci_div(mpci_gamma(znew, prec+2, 0), z, prec)
  813. if type == 2: return mpci_mul(mpci_gamma(znew, prec+2, 2), z, prec)
  814. if type == 3: return mpci_sub(mpci_gamma(znew, prec+2, 3), mpci_log(z,prec+2), prec)
  815. # Use monotonicity (except for a small region close to the
  816. # origin and near poles)
  817. # upper half-plane
  818. if mpf_ge(b1, fzero):
  819. minre = mpc_loggamma((a1,b2), wp, round_floor)
  820. maxre = mpc_loggamma((a2,b1), wp, round_ceiling)
  821. minim = mpc_loggamma((a1,b1), wp, round_floor)
  822. maxim = mpc_loggamma((a2,b2), wp, round_ceiling)
  823. # lower half-plane
  824. elif mpf_le(b2, fzero):
  825. minre = mpc_loggamma((a1,b1), wp, round_floor)
  826. maxre = mpc_loggamma((a2,b2), wp, round_ceiling)
  827. minim = mpc_loggamma((a2,b1), wp, round_floor)
  828. maxim = mpc_loggamma((a1,b2), wp, round_ceiling)
  829. # crosses real axis
  830. else:
  831. maxre = mpc_loggamma((a2,fzero), wp, round_ceiling)
  832. # stretches more into the lower half-plane
  833. if mpf_gt(mpf_neg(b1), b2):
  834. minre = mpc_loggamma((a1,b1), wp, round_ceiling)
  835. else:
  836. minre = mpc_loggamma((a1,b2), wp, round_ceiling)
  837. minim = mpc_loggamma((a2,b1), wp, round_floor)
  838. maxim = mpc_loggamma((a2,b2), wp, round_floor)
  839. w = (minre[0], maxre[0]), (minim[1], maxim[1])
  840. if type == 3:
  841. return mpi_pos(w[0], prec), mpi_pos(w[1], prec)
  842. if type == 2:
  843. w = mpci_neg(w)
  844. return mpci_exp(w, prec)
  845. def mpi_loggamma(z, prec): return mpi_gamma(z, prec, type=3)
  846. def mpci_loggamma(z, prec): return mpci_gamma(z, prec, type=3)
  847. def mpi_rgamma(z, prec): return mpi_gamma(z, prec, type=2)
  848. def mpci_rgamma(z, prec): return mpci_gamma(z, prec, type=2)
  849. def mpi_factorial(z, prec): return mpi_gamma(z, prec, type=1)
  850. def mpci_factorial(z, prec): return mpci_gamma(z, prec, type=1)