libmpi.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935
  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)