def mpc_expjpi(z, prec, rnd="f"): re, im = z if im == fzero: return mpf_cos_sin_pi(re, prec, rnd) sign, man, exp, bc = im wp = prec + 10 if man: wp += max(0, exp + bc) im = mpf_neg(mpf_mul(mpf_pi(wp), im, wp)) if re == fzero: return mpf_exp(im, prec, rnd), fzero ey = mpf_exp(im, prec + 10) c, s = mpf_cos_sin_pi(re, prec + 10) re = mpf_mul(ey, c, prec, rnd) im = mpf_mul(ey, s, prec, rnd) return re, im
def mpf_psi0(x, prec, rnd=round_fast): """ Computation of the digamma function (psi function of order 0) of a real argument. """ sign, man, exp, bc = x wp = prec + 10 if not man: if x == finf: return x if x == fninf or x == fnan: return fnan if x == fzero or (exp >= 0 and sign): raise ValueError("polygamma pole") # Reflection formula if sign and exp + bc > 3: c, s = mpf_cos_sin_pi(x, wp) q = mpf_mul(mpf_div(c, s, wp), mpf_pi(wp), wp) p = mpf_psi0(mpf_sub(fone, x, wp), wp) return mpf_sub(p, q, prec, rnd) # The logarithmic term is accurate enough if (not sign) and bc + exp > wp: return mpf_log(mpf_sub(x, fone, wp), prec, rnd) # Initial recurrence to obtain a large enough x m = to_int(x) n = int(0.11 * wp) + 2 s = MP_ZERO x = to_fixed(x, wp) one = MP_ONE << wp if m < n: for k in xrange(m, n): s -= (one << wp) // x x += one x -= one # Logarithmic term s += to_fixed(mpf_log(from_man_exp(x, -wp, wp), wp), wp) # Endpoint term in Euler-Maclaurin expansion s += (one << wp) // (2 * x) # Euler-Maclaurin remainder sum x2 = (x * x) >> wp t = one prev = 0 k = 1 while 1: t = (t * x2) >> wp bsign, bman, bexp, bbc = mpf_bernoulli(2 * k, wp) offset = bexp + 2 * wp if offset >= 0: term = (bman << offset) // (t * (2 * k)) else: term = (bman >> (-offset)) // (t * (2 * k)) if k & 1: s -= term else: s += term if k > 2 and term >= prev: break prev = term k += 1 return from_man_exp(s, -wp, wp, rnd)
def mpc_expjpi(z, prec, rnd='f'): re, im = z if im == fzero: return mpf_cos_sin_pi(re, prec, rnd) sign, man, exp, bc = im wp = prec + 10 if man: wp += max(0, exp + bc) im = mpf_neg(mpf_mul(mpf_pi(wp), im, wp)) if re == fzero: return mpf_exp(im, prec, rnd), fzero ey = mpf_exp(im, prec + 10) c, s = mpf_cos_sin_pi(re, prec + 10) re = mpf_mul(ey, c, prec, rnd) im = mpf_mul(ey, s, prec, rnd) return re, im
def mpc_cos_sin_pi(z, prec, rnd=round_fast): a, b = z if b == fzero: c, s = mpf_cos_sin_pi(a, prec, rnd) return (c, fzero), (s, fzero) b = mpf_mul(b, mpf_pi(prec + 5), prec + 5) if a == fzero: ch, sh = mpf_cosh_sinh(b, prec, rnd) return (ch, fzero), (fzero, sh) wp = prec + 6 c, s = mpf_cos_sin_pi(a, wp) ch, sh = mpf_cosh_sinh(b, wp) cre = mpf_mul(c, ch, prec, rnd) cim = mpf_mul(s, sh, prec, rnd) sre = mpf_mul(s, ch, prec, rnd) sim = mpf_mul(c, sh, prec, rnd) return (cre, mpf_neg(cim)), (sre, sim)
def mpc_sin_pi(z, prec, rnd=round_fast): a, b = z b = mpf_mul(b, mpf_pi(prec+5), prec+5) if a == fzero: return fzero, mpf_sinh(b, prec, rnd) wp = prec + 6 c, s = mpf_cos_sin_pi(a, wp) ch, sh = mpf_cosh_sinh(b, wp) re = mpf_mul(s, ch, prec, rnd) im = mpf_mul(c, sh, prec, rnd) return re, im
def mpf_psi0(x, prec, rnd=round_fast): """ Computation of the digamma function (psi function of order 0) of a real argument. """ sign, man, exp, bc = x wp = prec + 10 if not man: if x == finf: return x if x == fninf or x == fnan: return fnan if x == fzero or (exp >= 0 and sign): raise ValueError("polygamma pole") # Reflection formula if sign and exp + bc > 3: c, s = mpf_cos_sin_pi(x, wp) q = mpf_mul(mpf_div(c, s, wp), mpf_pi(wp), wp) p = mpf_psi0(mpf_sub(fone, x, wp), wp) return mpf_sub(p, q, prec, rnd) # The logarithmic term is accurate enough if (not sign) and bc + exp > wp: return mpf_log(mpf_sub(x, fone, wp), prec, rnd) # Initial recurrence to obtain a large enough x m = to_int(x) n = int(0.11 * wp) + 2 s = MP_ZERO x = to_fixed(x, wp) one = MP_ONE << wp if m < n: for k in xrange(m, n): s -= (one << wp) // x x += one x -= one # Logarithmic term s += to_fixed(mpf_log(from_man_exp(x, -wp, wp), wp), wp) # Endpoint term in Euler-Maclaurin expansion s += (one << wp) // (2 * x) # Euler-Maclaurin remainder sum x2 = (x * x) >> wp t = one prev = 0 k = 1 while 1: t = (t * x2) >> wp bsign, bman, bexp, bbc = mpf_bernoulli(2 * k, wp) offset = (bexp + 2 * wp) if offset >= 0: term = (bman << offset) // (t * (2 * k)) else: term = (bman >> (-offset)) // (t * (2 * k)) if k & 1: s -= term else: s += term if k > 2 and term >= prev: break prev = term k += 1 return from_man_exp(s, -wp, wp, rnd)
def mpc_sin_pi(z, prec, rnd=round_fast): a, b = z b = mpf_mul(b, mpf_pi(prec + 5), prec + 5) if a == fzero: return fzero, mpf_sinh(b, prec, rnd) wp = prec + 6 c, s = mpf_cos_sin_pi(a, wp) ch, sh = mpf_cosh_sinh(b, wp) re = mpf_mul(s, ch, prec, rnd) im = mpf_mul(c, sh, prec, rnd) return re, im
def mpc_cos_pi(z, prec, rnd=round_fast): a, b = z if b == fzero: return mpf_cos_pi(a, prec, rnd), fzero b = mpf_mul(b, mpf_pi(prec + 5), prec + 5) if a == fzero: return mpf_cosh(b, prec, rnd), fzero wp = prec + 6 c, s = mpf_cos_sin_pi(a, wp) ch, sh = mpf_cosh_sinh(b, wp) re = mpf_mul(c, ch, prec, rnd) im = mpf_mul(s, sh, prec, rnd) return re, mpf_neg(im)
a = mpf_shift(a, 1) b = mpf_shift(b, 1) c, s = cos_sin(a, wp) ch, sh = cosh_sinh(b, wp) # TODO: handle cancellation when c ~= -1 and ch ~= 1 mag = mpf_add(c, ch, wp) re = mpf_div(s, mag, prec, rnd) im = mpf_div(sh, mag, prec, rnd) return re, im def mpc_cos_pi((a, b), prec, rnd=round_fast): b = mpf_mul(b, mpf_pi(prec+5), prec+5) if a == fzero: return mpf_cosh(b, prec, rnd), fzero wp = prec + 6 c, s = mpf_cos_sin_pi(a, wp) ch, sh = cosh_sinh(b, wp) re = mpf_mul(c, ch, prec, rnd) im = mpf_mul(s, sh, prec, rnd) return re, mpf_neg(im) def mpc_sin_pi((a, b), prec, rnd=round_fast): b = mpf_mul(b, mpf_pi(prec+5), prec+5) if a == fzero: return fzero, mpf_sinh(b, prec, rnd) wp = prec + 6 c, s = mpf_cos_sin_pi(a, wp) ch, sh = cosh_sinh(b, wp) re = mpf_mul(s, ch, prec, rnd) im = mpf_mul(c, sh, prec, rnd) return re, im