def mpf_cos_sin_pi(x, prec, rnd=round_fast): """Accurate computation of (cos(pi*x), sin(pi*x)) for x close to an integer""" sign, man, exp, bc = x if not man: return cos_sin(x, prec, rnd) # Exactly an integer or half-integer? if exp >= -1: if exp == -1: c = fzero s = (fone, fnone)[bool(man & 2) ^ sign] elif exp == 0: c, s = (fnone, fzero) else: c, s = (fone, fzero) return c, s # Close to 0 ? size = exp + bc if size < -(prec + 5): return (fone, mpf_mul(x, mpf_pi(wp), prec, rnd)) if sign: man = -man # Subtract nearest integer (= modulo pi) nint = ((man >> (-exp - 1)) + 1) >> 1 man = man - (nint << (-exp)) x = from_man_exp(man, exp, prec) x = mpf_mul(x, mpf_pi(prec), prec) # Shifted an odd multiple of pi ? if nint & 1: c, s = cos_sin(x, prec, negative_rnd[rnd]) return mpf_neg(c), mpf_neg(s) else: return cos_sin(x, prec, rnd)
def mpf_ellipe(x, prec, rnd=round_fast): # http://functions.wolfram.com/EllipticIntegrals/ # EllipticK/20/01/0001/ # E = (1-m)*(K'(m)*2*m + K(m)) sign, man, exp, bc = x if not man: if x == fzero: return mpf_shift(mpf_pi(prec, rnd), -1) if x == fninf: return finf if x == fnan: return x if x == finf: raise ComplexResult if x == fone: return fone wp = prec+20 mag = exp+bc if mag < -wp: return mpf_shift(mpf_pi(prec, rnd), -1) # Compute a finite difference for K' p = max(mag, 0) - wp h = mpf_shift(fone, p) K = mpf_ellipk(x, 2*wp) Kh = mpf_ellipk(mpf_sub(x, h), 2*wp) Kdiff = mpf_shift(mpf_sub(K, Kh), -p) t = mpf_sub(fone, x) b = mpf_mul(Kdiff, mpf_shift(x,1), wp) return mpf_mul(t, mpf_add(K, b), prec, rnd)
def mpf_ellipe(x, prec, rnd=round_fast): # http://functions.wolfram.com/EllipticIntegrals/ # EllipticK/20/01/0001/ # E = (1-m)*(K'(m)*2*m + K(m)) sign, man, exp, bc = x if not man: if x == fzero: return mpf_shift(mpf_pi(prec, rnd), -1) if x == fninf: return finf if x == fnan: return x if x == finf: raise ComplexResult if x == fone: return fone wp = prec + 20 mag = exp + bc if mag < -wp: return mpf_shift(mpf_pi(prec, rnd), -1) # Compute a finite difference for K' p = max(mag, 0) - wp h = mpf_shift(fone, p) K = mpf_ellipk(x, 2 * wp) Kh = mpf_ellipk(mpf_sub(x, h), 2 * wp) Kdiff = mpf_shift(mpf_sub(K, Kh), -p) t = mpf_sub(fone, x) b = mpf_mul(Kdiff, mpf_shift(x, 1), wp) return mpf_mul(t, mpf_add(K, b), prec, rnd)
def mpf_cos_sin_pi(x, prec, rnd=round_fast): """Accurate computation of (cos(pi*x), sin(pi*x)) for x close to an integer""" sign, man, exp, bc = x if not man: return cos_sin(x, prec, rnd) # Exactly an integer or half-integer? if exp >= -1: if exp == -1: c = fzero s = (fone, fnone)[bool(man & 2) ^ sign] elif exp == 0: c, s = (fnone, fzero) else: c, s = (fone, fzero) return c, s # Close to 0 ? size = exp + bc if size < -(prec+5): return (fone, mpf_mul(x, mpf_pi(wp), prec, rnd)) if sign: man = -man # Subtract nearest integer (= modulo pi) nint = ((man >> (-exp-1)) + 1) >> 1 man = man - (nint << (-exp)) x = from_man_exp(man, exp, prec) x = mpf_mul(x, mpf_pi(prec), prec) # Shifted an odd multiple of pi ? if nint & 1: c, s = cos_sin(x, prec, negative_rnd[rnd]) return mpf_neg(c), mpf_neg(s) else: return cos_sin(x, prec, rnd)
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 khinchin_fixed(prec): wp = int(prec + prec**0.5 + 15) s = MPZ_ZERO fac = from_int(4) t = ONE = MPZ_ONE << wp pi = mpf_pi(wp) pipow = twopi2 = mpf_shift(mpf_mul(pi, pi, wp), 2) n = 1 while 1: zeta2n = mpf_abs(mpf_bernoulli(2*n, wp)) zeta2n = mpf_mul(zeta2n, pipow, wp) zeta2n = mpf_div(zeta2n, fac, wp) zeta2n = to_fixed(zeta2n, wp) term = (((zeta2n - ONE) * t) // n) >> wp if term < 100: break #if not n % 10: # print n, math.log(int(abs(term))) s += term t += ONE//(2*n+1) - ONE//(2*n) n += 1 fac = mpf_mul_int(fac, (2*n)*(2*n-1), wp) pipow = mpf_mul(pipow, twopi2, wp) s = (s << wp) // ln2_fixed(wp) K = mpf_exp(from_man_exp(s, -wp), wp) K = to_fixed(K, prec) return K
def mpc_zeta(s, prec, rnd=round_fast, alt=0): re, im = s if im == fzero: return mpf_zeta(re, prec, rnd, alt), fzero wp = prec + 20 # Reflection formula. To be rigorous, we should reflect to the left of # re = 1/2 (see comments for mpf_zeta), but this leads to unnecessary # slowdown for interesting values of s if mpf_lt(re, fzero): # XXX: could use the separate refl. formula for Dirichlet eta if alt: q = mpc_sub(mpc_one, mpc_pow(mpc_two, mpc_sub(mpc_one, s, wp), wp), wp) return mpc_mul(mpc_zeta(s, wp), q, prec, rnd) # XXX: -1 should be done exactly y = mpc_sub(mpc_one, s, 10*wp) a = mpc_gamma(y, wp) b = mpc_zeta(y, wp) c = mpc_sin_pi(mpc_shift(s, -1), wp) rsign, rman, rexp, rbc = re isign, iman, iexp, ibc = im mag = max(rexp+rbc, iexp+ibc) wp2 = wp + mag pi = mpf_pi(wp+wp2) pi2 = (mpf_shift(pi, 1), fzero) d = mpc_div_mpf(mpc_pow(pi2, s, wp2), pi, wp2) return mpc_mul(a,mpc_mul(b,mpc_mul(c,d,wp),wp),prec,rnd) n = int(wp/2.54 + 5) n += int(0.9*abs(to_int(im))) d = borwein_coefficients(n) ref = to_fixed(re, wp) imf = to_fixed(im, wp) tre = MP_ZERO tim = MP_ZERO one = MP_ONE << wp one_2wp = MP_ONE << (2*wp) critical_line = re == fhalf for k in xrange(n): log = log_int_fixed(k+1, wp) # A square root is much cheaper than an exp if critical_line: w = one_2wp // sqrt_fixed((k+1) << wp, wp) else: w = to_fixed(mpf_exp(from_man_exp(-ref*log, -2*wp), wp), wp) if k & 1: w *= (d[n] - d[k]) else: w *= (d[k] - d[n]) wre, wim = cos_sin(from_man_exp(-imf * log_int_fixed(k+1, wp), -2*wp), wp) tre += (w * to_fixed(wre, wp)) >> wp tim += (w * to_fixed(wim, wp)) >> wp tre //= (-d[n]) tim //= (-d[n]) tre = from_man_exp(tre, -wp, wp) tim = from_man_exp(tim, -wp, wp) if alt: return mpc_pos((tre, tim), prec, rnd) else: q = mpc_sub(mpc_one, mpc_pow(mpc_two, mpc_sub(mpc_one, s, wp), wp), wp) return mpc_div((tre, tim), q, prec, rnd)
def khinchin_fixed(prec): wp = int(prec + prec**0.5 + 15) s = MP_ZERO fac = from_int(4) t = ONE = MP_ONE << wp pi = mpf_pi(wp) pipow = twopi2 = mpf_shift(mpf_mul(pi, pi, wp), 2) n = 1 while 1: zeta2n = mpf_abs(mpf_bernoulli(2 * n, wp)) zeta2n = mpf_mul(zeta2n, pipow, wp) zeta2n = mpf_div(zeta2n, fac, wp) zeta2n = to_fixed(zeta2n, wp) term = (((zeta2n - ONE) * t) // n) >> wp if term < 100: break #if not n % 100: # print n, nstr(ln(term)) s += term t += ONE // (2 * n + 1) - ONE // (2 * n) n += 1 fac = mpf_mul_int(fac, (2 * n) * (2 * n - 1), wp) pipow = mpf_mul(pipow, twopi2, wp) s = (s << wp) // ln2_fixed(wp) K = mpf_exp(from_man_exp(s, -wp), wp) K = to_fixed(K, prec) return K
def mpf_bernoulli_huge(n, prec, rnd=None): wp = prec + 10 piprec = wp + int(math.log(n, 2)) v = mpf_gamma_int(n + 1, wp) v = mpf_mul(v, mpf_zeta_int(n, wp), wp) v = mpf_mul(v, mpf_pow_int(mpf_pi(piprec), -n, wp)) v = mpf_shift(v, 1 - n) if not n & 3: v = mpf_neg(v) return mpf_pos(v, prec, rnd or round_fast)
def mpf_bernoulli_huge(n, prec, rnd=None): wp = prec + 10 piprec = wp + int(math.log(n,2)) v = mpf_gamma_int(n+1, wp) v = mpf_mul(v, mpf_zeta_int(n, wp), wp) v = mpf_mul(v, mpf_pow_int(mpf_pi(piprec), -n, wp)) v = mpf_shift(v, 1-n) if not n & 3: v = mpf_neg(v) return mpf_pos(v, prec, rnd or round_fast)
def mpf_ellipk(x, prec, rnd=round_fast): if not x[1]: if x == fzero: return mpf_shift(mpf_pi(prec, rnd), -1) if x == fninf: return fzero if x == fnan: return x if x == fone: return finf # TODO: for |x| << 1/2, one could use fall back to # pi/2 * hyp2f1_rat((1,2),(1,2),(1,1), x) wp = prec + 15 # Use K(x) = pi/2/agm(1,a) where a = sqrt(1-x) # The sqrt raises ComplexResult if x > 0 a = mpf_sqrt(mpf_sub(fone, x, wp), wp) v = mpf_agm1(a, wp) r = mpf_div(mpf_pi(wp), v, prec, rnd) return mpf_shift(r, -1)
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_erf(z, prec, rnd=round_fast): re, im = z if im == fzero: return (mpf_erf(re, prec, rnd), fzero) wp = prec + 20 z2 = mpc_mul(z, z, prec+20) v = mpc_hyp1f1_rat((1,2), (3,2), mpc_neg(z2), wp, rnd) sqrtpi = mpf_sqrt(mpf_pi(wp), wp) c = mpf_rdiv_int(2, sqrtpi, wp) c = mpc_mul_mpf(z, c, wp) return mpc_mul(c, v, prec, rnd)
def mpc_gamma(x, prec, rounding=round_fast, p1=1): re, im = x if im == fzero: return mpf_gamma(re, prec, rounding, p1), fzero # More precision is needed for enormous x. sign, man, exp, bc = re isign, iman, iexp, ibc = im if re == fzero: size = iexp + ibc else: size = max(exp + bc, iexp + ibc) if size > 5: size = int(size * math.log(size, 2)) reflect = sign or (exp + bc < -1) wp = prec + max(0, size) + 25 # Near x = 0 pole (TODO: other poles) if p1: if size < -prec - 5: return mpc_add_mpf(mpc_div(mpc_one, x, 2*prec+10), \ mpf_neg(mpf_euler(2*prec+10)), prec, rounding) elif size < -5: wp += (-2 * size) if p1: # Should be done exactly! re_orig = re re = mpf_sub(re, fone, bc + abs(exp) + 2) x = re, im if reflect: # Reflection formula wp += 15 pi = mpf_pi(wp), fzero pix = mpc_mul(x, pi, wp) t = mpc_sin_pi(x, wp) u = mpc_sub(mpc_one, x, wp) g = mpc_gamma(u, wp) w = mpc_mul(t, g, wp) return mpc_div(pix, w, wp) # Extremely close to the real line? # XXX: reflection formula if iexp + ibc < -wp: a = mpf_gamma(re_orig, wp) b = mpf_psi0(re_orig, wp) gamma_diff = mpf_div(a, b, wp) return mpf_pos(a, prec, rounding), mpf_mul(gamma_diff, im, prec, rounding) sprec, a, c = get_spouge_coefficients(wp) s = spouge_sum_complex(re, im, sprec, a, c) # gamma = exp(log(x+a)*(x+0.5) - xpa) * s repa = mpf_add(re, from_int(a), wp) logxpa = mpc_log((repa, im), wp) reph = mpf_add(re, fhalf, wp) t = mpc_sub(mpc_mul(logxpa, (reph, im), wp), (repa, im), wp) t = mpc_mul(mpc_exp(t, wp), s, prec, rounding) return t
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_erf(z, prec, rnd=round_fast): re, im = z if im == fzero: return (mpf_erf(re, prec, rnd), fzero) wp = prec + 20 z2 = mpc_square(z, prec + 20) v = mpc_hyp1f1_rat((1, 2), (3, 2), mpc_neg(z2), wp, rnd) sqrtpi = mpf_sqrt(mpf_pi(wp), wp) c = mpf_rdiv_int(2, sqrtpi, wp) c = mpc_mul_mpf(z, c, wp) return mpc_mul(c, v, prec, rnd)
def mpc_ellipk(z, prec, rnd=round_fast): re, im = z if im == fzero: if re == finf: return mpc_zero if mpf_le(re, fone): return mpf_ellipk(re, prec, rnd), fzero wp = prec + 15 a = mpc_sqrt(mpc_sub(mpc_one, z, wp), wp) v = mpc_agm1(a, wp) r = mpc_mpf_div(mpf_pi(wp), v, prec, rnd) return mpc_shift(r, -1)
def mpc_gamma(x, prec, rounding=round_fast, p1=1): re, im = x if im == fzero: return mpf_gamma(re, prec, rounding, p1), fzero # More precision is needed for enormous x. sign, man, exp, bc = re isign, iman, iexp, ibc = im if re == fzero: size = iexp+ibc else: size = max(exp+bc, iexp+ibc) if size > 5: size = int(size * math.log(size,2)) reflect = sign or (exp+bc < -1) wp = prec + max(0, size) + 25 # Near x = 0 pole (TODO: other poles) if p1: if size < -prec-5: return mpc_add_mpf(mpc_div(mpc_one, x, 2*prec+10), \ mpf_neg(mpf_euler(2*prec+10)), prec, rounding) elif size < -5: wp += (-2*size) if p1: # Should be done exactly! re_orig = re re = mpf_sub(re, fone, bc+abs(exp)+2) x = re, im if reflect: # Reflection formula wp += 15 pi = mpf_pi(wp), fzero pix = mpc_mul(x, pi, wp) t = mpc_sin_pi(x, wp) u = mpc_sub(mpc_one, x, wp) g = mpc_gamma(u, wp) w = mpc_mul(t, g, wp) return mpc_div(pix, w, wp) # Extremely close to the real line? # XXX: reflection formula if iexp+ibc < -wp: a = mpf_gamma(re_orig, wp) b = mpf_psi0(re_orig, wp) gamma_diff = mpf_div(a, b, wp) return mpf_pos(a, prec, rounding), mpf_mul(gamma_diff, im, prec, rounding) sprec, a, c = get_spouge_coefficients(wp) s = spouge_sum_complex(re, im, sprec, a, c) # gamma = exp(log(x+a)*(x+0.5) - xpa) * s repa = mpf_add(re, from_int(a), wp) logxpa = mpc_log((repa, im), wp) reph = mpf_add(re, fhalf, wp) t = mpc_sub(mpc_mul(logxpa, (reph, im), wp), (repa, im), wp) t = mpc_mul(mpc_exp(t, wp), s, prec, rounding) return t
def mpc_ci(z, prec, rnd=round_fast): re, im = z if im == fzero: ci = mpf_ci_si(re, prec, rnd, 0)[0] if mpf_sign(re) < 0: return (ci, mpf_pi(prec, rnd)) return (ci, fzero) wp = prec + 20 cre, cim = mpc_ci_si_taylor(re, im, wp, 0) cre = mpf_add(cre, mpf_euler(wp), wp) ci = mpc_add((cre, cim), mpc_log(z, wp), prec, rnd) return ci
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)
def mpf_zeta(s, prec, rnd=round_fast): sign, man, exp, bc = s if not man: if s == fzero: return mpf_neg(fhalf) if s == finf: return fone return fnan wp = prec + 20 # First term vanishes? if (not sign) and (exp + bc > (math.log(wp, 2) + 2)): if rnd in (round_up, round_ceiling): return mpf_add(fone, mpf_shift(fone, -wp - 10), prec, rnd) return fone elif exp >= 0: return mpf_zeta_int(to_int(s), prec, rnd) # Less than 0.5? if sign or (exp + bc) < 0: # XXX: -1 should be done exactly y = mpf_sub(fone, s, 10 * wp) a = mpf_gamma(y, wp) b = mpf_zeta(y, wp) c = mpf_sin_pi(mpf_shift(s, -1), wp) wp2 = wp + (exp + bc) pi = mpf_pi(wp + wp2) d = mpf_div(mpf_pow(mpf_shift(pi, 1), s, wp2), pi, wp2) return mpf_mul(a, mpf_mul(b, mpf_mul(c, d, wp), wp), prec, rnd) t = MP_ZERO #wp += 16 - (prec & 15) # Use Borwein's algorithm n = int(wp / 2.54 + 5) d = borwein_coefficients(n) t = MP_ZERO sf = to_fixed(s, wp) for k in xrange(n): u = from_man_exp(-sf * log_int_fixed(k + 1, wp), -2 * wp, wp) esign, eman, eexp, ebc = mpf_exp(u, wp) offset = eexp + wp if offset >= 0: w = ((d[k] - d[n]) * eman) << offset else: w = ((d[k] - d[n]) * eman) >> (-offset) if k & 1: t -= w else: t += w t = t // (-d[n]) t = from_man_exp(t, -wp, wp) q = mpf_sub(fone, mpf_pow(ftwo, mpf_sub(fone, s, wp), wp), wp) return mpf_div(t, q, prec, rnd)
def mpc_psi0(z, prec, rnd=round_fast): """ Computation of the digamma function (psi function of order 0) of a complex argument. """ re, im = z # Fall back to the real case if im == fzero: return (mpf_psi0(re, prec, rnd), fzero) wp = prec + 20 sign, man, exp, bc = re # Reflection formula if sign and exp+bc > 3: c = mpc_cos_pi(z, wp) s = mpc_sin_pi(z, wp) q = mpc_mul_mpf(mpc_div(c, s, wp), mpf_pi(wp), wp) p = mpc_psi0(mpc_sub(mpc_one, z, wp), wp) return mpc_sub(p, q, prec, rnd) # Just the logarithmic term if (not sign) and bc + exp > wp: return mpc_log(mpc_sub(z, mpc_one, wp), prec, rnd) # Initial recurrence to obtain a large enough z w = to_int(re) n = int(0.11*wp) + 2 s = mpc_zero if w < n: for k in xrange(w, n): s = mpc_sub(s, mpc_reciprocal(z, wp), wp) z = mpc_add_mpf(z, fone, wp) z = mpc_sub(z, mpc_one, wp) # Logarithmic and endpoint term s = mpc_add(s, mpc_log(z, wp), wp) s = mpc_add(s, mpc_div(mpc_half, z, wp), wp) # Euler-Maclaurin remainder sum z2 = mpc_square(z, wp) t = mpc_one prev = mpc_zero k = 1 eps = mpf_shift(fone, -wp+2) while 1: t = mpc_mul(t, z2, wp) bern = mpf_bernoulli(2*k, wp) term = mpc_mpf_div(bern, mpc_mul_int(t, 2*k, wp), wp) s = mpc_sub(s, term, wp) szterm = mpc_abs(term, 10) if k > 2 and mpf_le(szterm, eps): break prev = term k += 1 return s
def mpc_psi0(z, prec, rnd=round_fast): """ Computation of the digamma function (psi function of order 0) of a complex argument. """ re, im = z # Fall back to the real case if im == fzero: return (mpf_psi0(re, prec, rnd), fzero) wp = prec + 20 sign, man, exp, bc = re # Reflection formula if sign and exp + bc > 3: c = mpc_cos_pi(z, wp) s = mpc_sin_pi(z, wp) q = mpc_mul(mpc_div(c, s, wp), (mpf_pi(wp), fzero), wp) p = mpc_psi0(mpc_sub(mpc_one, z, wp), wp) return mpc_sub(p, q, prec, rnd) # Just the logarithmic term if (not sign) and bc + exp > wp: return mpc_log(mpc_sub(z, mpc_one, wp), prec, rnd) # Initial recurrence to obtain a large enough z w = to_int(re) n = int(0.11 * wp) + 2 s = mpc_zero if w < n: for k in xrange(w, n): s = mpc_sub(s, mpc_div(mpc_one, z, wp), wp) z = mpc_add_mpf(z, fone, wp) z = mpc_sub(z, mpc_one, wp) # Logarithmic and endpoint term s = mpc_add(s, mpc_log(z, wp), wp) s = mpc_add(s, mpc_div(mpc_half, z, wp), wp) # Euler-Maclaurin remainder sum z2 = mpc_mul(z, z, wp) t = mpc_one prev = mpc_zero k = 1 eps = mpf_shift(fone, -wp + 2) while 1: t = mpc_mul(t, z2, wp) bern = mpf_bernoulli(2 * k, wp) term = mpc_div((bern, fzero), mpc_mul_int(t, 2 * k, wp), wp) s = mpc_sub(s, term, wp) szterm = mpc_abs(term, 10) if k > 2 and mpf_le(szterm, eps): break prev = term k += 1 return s
def mpf_zeta(s, prec, rnd=round_fast): sign, man, exp, bc = s if not man: if s == fzero: return mpf_neg(fhalf) if s == finf: return fone return fnan wp = prec + 20 # First term vanishes? if (not sign) and (exp + bc > (math.log(wp,2) + 2)): if rnd in (round_up, round_ceiling): return mpf_add(fone, mpf_shift(fone,-wp-10), prec, rnd) return fone elif exp >= 0: return mpf_zeta_int(to_int(s), prec, rnd) # Less than 0.5? if sign or (exp+bc) < 0: # XXX: -1 should be done exactly y = mpf_sub(fone, s, 10*wp) a = mpf_gamma(y, wp) b = mpf_zeta(y, wp) c = mpf_sin_pi(mpf_shift(s, -1), wp) wp2 = wp + (exp+bc) pi = mpf_pi(wp+wp2) d = mpf_div(mpf_pow(mpf_shift(pi, 1), s, wp2), pi, wp2) return mpf_mul(a,mpf_mul(b,mpf_mul(c,d,wp),wp),prec,rnd) t = MP_ZERO #wp += 16 - (prec & 15) # Use Borwein's algorithm n = int(wp/2.54 + 5) d = borwein_coefficients(n) t = MP_ZERO sf = to_fixed(s, wp) for k in xrange(n): u = from_man_exp(-sf*log_int_fixed(k+1, wp), -2*wp, wp) esign, eman, eexp, ebc = mpf_exp(u, wp) offset = eexp + wp if offset >= 0: w = ((d[k] - d[n]) * eman) << offset else: w = ((d[k] - d[n]) * eman) >> (-offset) if k & 1: t -= w else: t += w t = t // (-d[n]) t = from_man_exp(t, -wp, wp) q = mpf_sub(fone, mpf_pow(ftwo, mpf_sub(fone, s, wp), wp), wp) return mpf_div(t, q, prec, rnd)
def mpc_cos_sin_pi(z, prec, rnd=round_fast): a, b = z 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_cos_sin_pi(z, prec, rnd=round_fast): a, b = z 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_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_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 calc_spouge_coefficients(a, prec): wp = prec + int(a*1.4) c = [0] * a # b = exp(a-1) b = mpf_exp(from_int(a-1), wp) # e = exp(1) e = mpf_exp(fone, wp) # sqrt(2*pi) sq2pi = mpf_sqrt(mpf_shift(mpf_pi(wp), 1), wp) c[0] = to_fixed(sq2pi, prec) for k in xrange(1, a): # c[k] = ((-1)**(k-1) * (a-k)**k) * b / sqrt(a-k) term = mpf_mul_int(b, ((-1)**(k-1) * (a-k)**k), wp) term = mpf_div(term, mpf_sqrt(from_int(a-k), wp), wp) c[k] = to_fixed(term, prec) # b = b / (e * k) b = mpf_div(b, mpf_mul(e, from_int(k), wp), wp) return c
def calc_spouge_coefficients(a, prec): wp = prec + int(a * 1.4) c = [0] * a # b = exp(a-1) b = mpf_exp(from_int(a - 1), wp) # e = exp(1) e = mpf_exp(fone, wp) # sqrt(2*pi) sq2pi = mpf_sqrt(mpf_shift(mpf_pi(wp), 1), wp) c[0] = to_fixed(sq2pi, prec) for k in xrange(1, a): # c[k] = ((-1)**(k-1) * (a-k)**k) * b / sqrt(a-k) term = mpf_mul_int(b, ((-1)**(k - 1) * (a - k)**k), wp) term = mpf_div(term, mpf_sqrt(from_int(a - k), wp), wp) c[k] = to_fixed(term, prec) # b = b / (e * k) b = mpf_div(b, mpf_mul(e, from_int(k), wp), wp) return c
def mpf_gamma(x, prec, rounding=round_fast, p1=1): """ Computes the gamma function of a real floating-point argument. With p1=0, computes a factorial instead. """ sign, man, exp, bc = x if not man: if x == finf: return finf if x == fninf or x == fnan: return fnan # More precision is needed for enormous x. TODO: # use Stirling's formula + Euler-Maclaurin summation size = exp + bc if size > 5: size = int(size * math.log(size,2)) wp = prec + max(0, size) + 15 if exp >= 0: if sign or (p1 and not man): raise ValueError("gamma function pole") # A direct factorial is fastest if exp + bc <= 10: return from_int(ifac((man<<exp)-p1), prec, rounding) reflect = sign or exp+bc < -1 if p1: # Should be done exactly! x = mpf_sub(x, fone) # x < 0.25 if reflect: # gamma = pi / (sin(pi*x) * gamma(1-x)) wp += 15 pix = mpf_mul(x, mpf_pi(wp), wp) t = mpf_sin_pi(x, wp) g = mpf_gamma(mpf_sub(fone, x), wp) return mpf_div(pix, mpf_mul(t, g, wp), prec, rounding) sprec, a, c = get_spouge_coefficients(wp) s = spouge_sum_real(x, sprec, a, c) # gamma = exp(log(x+a)*(x+0.5) - xpa) * s xpa = mpf_add(x, from_int(a), wp) logxpa = mpf_log(xpa, wp) xph = mpf_add(x, fhalf, wp) t = mpf_sub(mpf_mul(logxpa, xph, wp), xpa, wp) t = mpf_mul(mpf_exp(t, wp), s, prec, rounding) return t
def mpf_gamma(x, prec, rounding=round_fast, p1=1): """ Computes the gamma function of a real floating-point argument. With p1=0, computes a factorial instead. """ sign, man, exp, bc = x if not man: if x == finf: return finf if x == fninf or x == fnan: return fnan # More precision is needed for enormous x. TODO: # use Stirling's formula + Euler-Maclaurin summation size = exp + bc if size > 5: size = int(size * math.log(size, 2)) wp = prec + max(0, size) + 15 if exp >= 0: if sign or (p1 and not man): raise ValueError("gamma function pole") # A direct factorial is fastest if exp + bc <= 10: return from_int(int_fac((man << exp) - p1), prec, rounding) reflect = sign or exp + bc < -1 if p1: # Should be done exactly! x = mpf_sub(x, fone, bc - exp + 2) # x < 0.25 if reflect: # gamma = pi / (sin(pi*x) * gamma(1-x)) wp += 15 pix = mpf_mul(x, mpf_pi(wp), wp) t = mpf_sin_pi(x, wp) g = mpf_gamma(mpf_sub(fone, x, wp), wp) return mpf_div(pix, mpf_mul(t, g, wp), prec, rounding) sprec, a, c = get_spouge_coefficients(wp) s = spouge_sum_real(x, sprec, a, c) # gamma = exp(log(x+a)*(x+0.5) - xpa) * s xpa = mpf_add(x, from_int(a), wp) logxpa = mpf_log(xpa, wp) xph = mpf_add(x, fhalf, wp) t = mpf_sub(mpf_mul(logxpa, xph, wp), xpa, wp) t = mpf_mul(mpf_exp(t, wp), s, prec, rounding) return t
def mpf_erf(x, prec, rnd=round_fast): sign, man, exp, bc = x if not man: if x == fzero: return fzero if x == finf: return fone if x == fninf: return fnone return fnan size = exp + bc lg = math.log # The approximation erf(x) = 1 is accurate to > x^2 * log(e,2) bits if size > 3 and 2 * (size - 1) + 0.528766 > lg(prec, 2): if sign: return mpf_perturb(fnone, 0, prec, rnd) else: return mpf_perturb(fone, 1, prec, rnd) # erf(x) ~ 2*x/sqrt(pi) close to 0 if size < -prec: # 2*x x = mpf_shift(x, 1) c = mpf_sqrt(mpf_pi(prec + 20), prec + 20) # TODO: interval rounding return mpf_div(x, c, prec, rnd) wp = prec + abs(size) + 20 # Taylor series for erf, fixed-point summation t = abs(to_fixed(x, wp)) t2 = (t * t) >> wp s, term, k = t, 12345, 1 while term: t = ((t * t2) >> wp) // k term = t // (2 * k + 1) if k & 1: s -= term else: s += term k += 1 s = (s << (wp + 1)) // sqrt_fixed(pi_fixed(wp), wp) if sign: s = -s return from_man_exp(s, -wp, wp, rnd)
def mpf_erf(x, prec, rnd=round_fast): sign, man, exp, bc = x if not man: if x == fzero: return fzero if x == finf: return fone if x== fninf: return fnone return fnan size = exp + bc lg = math.log # The approximation erf(x) = 1 is accurate to > x^2 * log(e,2) bits if size > 3 and 2*(size-1) + 0.528766 > lg(prec,2): if sign: return mpf_perturb(fnone, 0, prec, rnd) else: return mpf_perturb(fone, 1, prec, rnd) # erf(x) ~ 2*x/sqrt(pi) close to 0 if size < -prec: # 2*x x = mpf_shift(x,1) c = mpf_sqrt(mpf_pi(prec+20), prec+20) # TODO: interval rounding return mpf_div(x, c, prec, rnd) wp = prec + abs(size) + 25 # Taylor series for erf, fixed-point summation t = abs(to_fixed(x, wp)) t2 = (t*t) >> wp s, term, k = t, 12345, 1 while term: t = ((t * t2) >> wp) // k term = t // (2*k+1) if k & 1: s -= term else: s += term k += 1 s = (s << (wp+1)) // sqrt_fixed(pi_fixed(wp), wp) if sign: s = -s return from_man_exp(s, -wp, prec, rnd)
def mpi_atan2(y, x, prec): ya, yb = y xa, xb = x # Constrained to the real line if ya == yb == fzero: if mpf_ge(xa, fzero): return mpi_zero return mpi_pi(prec) # Right half-plane if mpf_ge(xa, fzero): if mpf_ge(ya, fzero): a = mpf_atan2(ya, xb, prec, round_floor) else: a = mpf_atan2(ya, xa, prec, round_floor) if mpf_ge(yb, fzero): b = mpf_atan2(yb, xa, prec, round_ceiling) else: b = mpf_atan2(yb, xb, prec, round_ceiling) # Upper half-plane elif mpf_ge(ya, fzero): b = mpf_atan2(ya, xa, prec, round_ceiling) if mpf_le(xb, fzero): a = mpf_atan2(yb, xb, prec, round_floor) else: a = mpf_atan2(ya, xb, prec, round_floor) # Lower half-plane elif mpf_le(yb, fzero): a = mpf_atan2(yb, xa, prec, round_floor) if mpf_le(xb, fzero): b = mpf_atan2(ya, xb, prec, round_ceiling) else: b = mpf_atan2(yb, xb, prec, round_ceiling) # Covering the origin else: b = mpf_pi(prec, round_ceiling) a = mpf_neg(b) return a, b
def acos_asin(z, prec, rnd, n): """ complex acos for n = 0, asin for n = 1 The algorithm is described in T.E. Hull, T.F. Fairgrieve and P.T.P. Tang 'Implementing the Complex Arcsine and Arcosine Functions using Exception Handling', ACM Trans. on Math. Software Vol. 23 (1997), p299 The complex acos and asin can be defined as acos(z) = acos(beta) - I*sign(a)* log(alpha + sqrt(alpha**2 -1)) asin(z) = asin(beta) + I*sign(a)* log(alpha + sqrt(alpha**2 -1)) where z = a + I*b alpha = (1/2)*(r + s); beta = (1/2)*(r - s) = a/alpha r = sqrt((a+1)**2 + y**2); s = sqrt((a-1)**2 + y**2) These expressions are rewritten in different ways in different regions, delimited by two crossovers alpha_crossover and beta_crossover, and by abs(a) <= 1, in order to improve the numerical accuracy. """ a, b = z wp = prec + 10 # special cases with real argument if b == fzero: am = mpf_sub(fone, mpf_abs(a), wp) # case abs(a) <= 1 if not am[0]: if n == 0: return mpf_acos(a, prec, rnd), fzero else: return mpf_asin(a, prec, rnd), fzero # cases abs(a) > 1 else: # case a < -1 if a[0]: pi = mpf_pi(prec, rnd) c = mpf_acosh(mpf_neg(a), prec, rnd) if n == 0: return pi, mpf_neg(c) else: return mpf_neg(mpf_shift(pi, -1)), c # case a > 1 else: c = mpf_acosh(a, prec, rnd) if n == 0: return fzero, c else: pi = mpf_pi(prec, rnd) return mpf_shift(pi, -1), mpf_neg(c) asign = bsign = 0 if a[0]: a = mpf_neg(a) asign = 1 if b[0]: b = mpf_neg(b) bsign = 1 am = mpf_sub(fone, a, wp) ap = mpf_add(fone, a, wp) r = mpf_hypot(ap, b, wp) s = mpf_hypot(am, b, wp) alpha = mpf_shift(mpf_add(r, s, wp), -1) beta = mpf_div(a, alpha, wp) b2 = mpf_mul(b, b, wp) # case beta <= beta_crossover if not mpf_sub(beta_crossover, beta, wp)[0]: if n == 0: re = mpf_acos(beta, wp) else: re = mpf_asin(beta, wp) else: # to compute the real part in this region use the identity # asin(beta) = atan(beta/sqrt(1-beta**2)) # beta/sqrt(1-beta**2) = (alpha + a) * (alpha - a) # alpha + a is numerically accurate; alpha - a can have # cancellations leading to numerical inaccuracies, so rewrite # it in differente ways according to the region Ax = mpf_add(alpha, a, wp) # case a <= 1 if not am[0]: # c = b*b/(r + (a+1)); d = (s + (1-a)) # alpha - a = (1/2)*(c + d) # case n=0: re = atan(sqrt((1/2) * Ax * (c + d))/a) # case n=1: re = atan(a/sqrt((1/2) * Ax * (c + d))) c = mpf_div(b2, mpf_add(r, ap, wp), wp) d = mpf_add(s, am, wp) re = mpf_shift(mpf_mul(Ax, mpf_add(c, d, wp), wp), -1) if n == 0: re = mpf_atan(mpf_div(mpf_sqrt(re, wp), a, wp), wp) else: re = mpf_atan(mpf_div(a, mpf_sqrt(re, wp), wp), wp) else: # c = Ax/(r + (a+1)); d = Ax/(s - (1-a)) # alpha - a = (1/2)*(c + d) # case n = 0: re = atan(b*sqrt(c + d)/2/a) # case n = 1: re = atan(a/(b*sqrt(c + d)/2) c = mpf_div(Ax, mpf_add(r, ap, wp), wp) d = mpf_div(Ax, mpf_sub(s, am, wp), wp) re = mpf_shift(mpf_add(c, d, wp), -1) re = mpf_mul(b, mpf_sqrt(re, wp), wp) if n == 0: re = mpf_atan(mpf_div(re, a, wp), wp) else: re = mpf_atan(mpf_div(a, re, wp), wp) # to compute alpha + sqrt(alpha**2 - 1), if alpha <= alpha_crossover # replace it with 1 + Am1 + sqrt(Am1*(alpha+1))) # where Am1 = alpha -1 # if alpha <= alpha_crossover: if not mpf_sub(alpha_crossover, alpha, wp)[0]: c1 = mpf_div(b2, mpf_add(r, ap, wp), wp) # case a < 1 if mpf_neg(am)[0]: # Am1 = (1/2) * (b*b/(r + (a+1)) + b*b/(s + (1-a)) c2 = mpf_add(s, am, wp) c2 = mpf_div(b2, c2, wp) Am1 = mpf_shift(mpf_add(c1, c2, wp), -1) else: # Am1 = (1/2) * (b*b/(r + (a+1)) + (s - (1-a))) c2 = mpf_sub(s, am, wp) Am1 = mpf_shift(mpf_add(c1, c2, wp), -1) # im = log(1 + Am1 + sqrt(Am1*(alpha+1))) im = mpf_mul(Am1, mpf_add(alpha, fone, wp), wp) im = mpf_log(mpf_add(fone, mpf_add(Am1, mpf_sqrt(im, wp), wp), wp), wp) else: # im = log(alpha + sqrt(alpha*alpha - 1)) im = mpf_sqrt(mpf_sub(mpf_mul(alpha, alpha, wp), fone, wp), wp) im = mpf_log(mpf_add(alpha, im, wp), wp) if asign: if n == 0: re = mpf_sub(mpf_pi(wp), re, wp) else: re = mpf_neg(re) if not bsign and n == 0: im = mpf_neg(im) if bsign and n == 1: im = mpf_neg(im) re = normalize(re[0], re[1], re[2], re[3], prec, rnd) im = normalize(im[0], im[1], im[2], im[3], prec, rnd) return re, im
def mpc_zeta(s, prec, rnd=round_fast, alt=0, force=False): re, im = s if im == fzero: return mpf_zeta(re, prec, rnd, alt), fzero # slow for large s if (not force) and mpf_gt(mpc_abs(s, 10), from_int(prec)): raise NotImplementedError wp = prec + 20 # Near pole r = mpc_sub(mpc_one, s, wp) asign, aman, aexp, abc = mpc_abs(r, 10) pole_dist = -2*(aexp+abc) if pole_dist > wp: if alt: q = mpf_ln2(wp) y = mpf_mul(q, mpf_euler(wp), wp) g = mpf_shift(mpf_mul(q, q, wp), -1) g = mpf_sub(y, g) z = mpc_mul_mpf(r, mpf_neg(g), wp) z = mpc_add_mpf(z, q, wp) return mpc_pos(z, prec, rnd) else: q = mpc_neg(mpc_div(mpc_one, r, wp)) q = mpc_add_mpf(q, mpf_euler(wp), wp) return mpc_pos(q, prec, rnd) else: wp += max(0, pole_dist) # Reflection formula. To be rigorous, we should reflect to the left of # re = 1/2 (see comments for mpf_zeta), but this leads to unnecessary # slowdown for interesting values of s if mpf_lt(re, fzero): # XXX: could use the separate refl. formula for Dirichlet eta if alt: q = mpc_sub(mpc_one, mpc_pow(mpc_two, mpc_sub(mpc_one, s, wp), wp), wp) return mpc_mul(mpc_zeta(s, wp), q, prec, rnd) # XXX: -1 should be done exactly y = mpc_sub(mpc_one, s, 10*wp) a = mpc_gamma(y, wp) b = mpc_zeta(y, wp) c = mpc_sin_pi(mpc_shift(s, -1), wp) rsign, rman, rexp, rbc = re isign, iman, iexp, ibc = im mag = max(rexp+rbc, iexp+ibc) wp2 = wp + mag pi = mpf_pi(wp+wp2) pi2 = (mpf_shift(pi, 1), fzero) d = mpc_div_mpf(mpc_pow(pi2, s, wp2), pi, wp2) return mpc_mul(a,mpc_mul(b,mpc_mul(c,d,wp),wp),prec,rnd) n = int(wp/2.54 + 5) n += int(0.9*abs(to_int(im))) d = borwein_coefficients(n) ref = to_fixed(re, wp) imf = to_fixed(im, wp) tre = MPZ_ZERO tim = MPZ_ZERO one = MPZ_ONE << wp one_2wp = MPZ_ONE << (2*wp) critical_line = re == fhalf for k in xrange(n): log = log_int_fixed(k+1, wp) # A square root is much cheaper than an exp if critical_line: w = one_2wp // sqrt_fixed((k+1) << wp, wp) else: w = to_fixed(mpf_exp(from_man_exp(-ref*log, -2*wp), wp), wp) if k & 1: w *= (d[n] - d[k]) else: w *= (d[k] - d[n]) wre, wim = mpf_cos_sin(from_man_exp(-imf * log, -2*wp), wp) tre += (w * to_fixed(wre, wp)) >> wp tim += (w * to_fixed(wim, wp)) >> wp tre //= (-d[n]) tim //= (-d[n]) tre = from_man_exp(tre, -wp, wp) tim = from_man_exp(tim, -wp, wp) if alt: return mpc_pos((tre, tim), prec, rnd) else: q = mpc_sub(mpc_one, mpc_pow(mpc_two, r, wp), wp) return mpc_div((tre, tim), q, prec, rnd)
def mpf_zeta(s, prec, rnd=round_fast, alt=0): sign, man, exp, bc = s if not man: if s == fzero: if alt: return fhalf else: return mpf_neg(fhalf) if s == finf: return fone return fnan wp = prec + 20 # First term vanishes? if (not sign) and (exp + bc > (math.log(wp,2) + 2)): return mpf_perturb(fone, alt, prec, rnd) # Optimize for integer arguments elif exp >= 0: if alt: if s == fone: return mpf_ln2(prec, rnd) z = mpf_zeta_int(to_int(s), wp, negative_rnd[rnd]) q = mpf_sub(fone, mpf_pow(ftwo, mpf_sub(fone, s, wp), wp), wp) return mpf_mul(z, q, prec, rnd) else: return mpf_zeta_int(to_int(s), prec, rnd) # Negative: use the reflection formula # Borwein only proves the accuracy bound for x >= 1/2. However, based on # tests, the accuracy without reflection is quite good even some distance # to the left of 1/2. XXX: verify this. if sign: # XXX: could use the separate refl. formula for Dirichlet eta if alt: q = mpf_sub(fone, mpf_pow(ftwo, mpf_sub(fone, s, wp), wp), wp) return mpf_mul(mpf_zeta(s, wp), q, prec, rnd) # XXX: -1 should be done exactly y = mpf_sub(fone, s, 10*wp) a = mpf_gamma(y, wp) b = mpf_zeta(y, wp) c = mpf_sin_pi(mpf_shift(s, -1), wp) wp2 = wp + (exp+bc) pi = mpf_pi(wp+wp2) d = mpf_div(mpf_pow(mpf_shift(pi, 1), s, wp2), pi, wp2) return mpf_mul(a,mpf_mul(b,mpf_mul(c,d,wp),wp),prec,rnd) # Near pole r = mpf_sub(fone, s, wp) asign, aman, aexp, abc = mpf_abs(r) pole_dist = -2*(aexp+abc) if pole_dist > wp: if alt: return mpf_ln2(prec, rnd) else: q = mpf_neg(mpf_div(fone, r, wp)) return mpf_add(q, mpf_euler(wp), prec, rnd) else: wp += max(0, pole_dist) t = MPZ_ZERO #wp += 16 - (prec & 15) # Use Borwein's algorithm n = int(wp/2.54 + 5) d = borwein_coefficients(n) t = MPZ_ZERO sf = to_fixed(s, wp) for k in xrange(n): u = from_man_exp(-sf*log_int_fixed(k+1, wp), -2*wp, wp) esign, eman, eexp, ebc = mpf_exp(u, wp) offset = eexp + wp if offset >= 0: w = ((d[k] - d[n]) * eman) << offset else: w = ((d[k] - d[n]) * eman) >> (-offset) if k & 1: t -= w else: t += w t = t // (-d[n]) t = from_man_exp(t, -wp, wp) if alt: return mpf_pos(t, prec, rnd) else: q = mpf_sub(fone, mpf_pow(ftwo, mpf_sub(fone, s, wp), wp), wp) return mpf_div(t, q, prec, rnd)
def mpf_ci_si(x, prec, rnd=round_fast, which=2): """ Calculation of Ci(x), Si(x) for real x. which = 0 -- returns (Ci(x), -) which = 1 -- returns (Si(x), -) which = 2 -- returns (Ci(x), Si(x)) Note: if x < 0, Ci(x) needs an additional imaginary term, pi*i. """ wp = prec + 20 sign, man, exp, bc = x ci, si = None, None if not man: if x == fzero: return (fninf, fzero) if x == fnan: return (x, x) ci = fzero if which != 0: if x == finf: si = mpf_shift(mpf_pi(prec, rnd), -1) if x == fninf: si = mpf_neg(mpf_shift(mpf_pi(prec, negative_rnd[rnd]), -1)) return (ci, si) # For small x: Ci(x) ~ euler + log(x), Si(x) ~ x mag = exp+bc if mag < -wp: if which != 0: si = mpf_perturb(x, 1-sign, prec, rnd) if which != 1: y = mpf_euler(wp) xabs = mpf_abs(x) ci = mpf_add(y, mpf_log(xabs, wp), prec, rnd) return ci, si # For huge x: Ci(x) ~ sin(x)/x, Si(x) ~ pi/2 elif mag > wp: if which != 0: if sign: si = mpf_neg(mpf_pi(prec, negative_rnd[rnd])) else: si = mpf_pi(prec, rnd) si = mpf_shift(si, -1) if which != 1: ci = mpf_div(mpf_sin(x, wp), x, prec, rnd) return ci, si else: wp += abs(mag) # Use an asymptotic series? The smallest value of n!/x^n # occurs for n ~ x, where the magnitude is ~ exp(-x). asymptotic = mag-1 > math.log(wp, 2) # Case 1: convergent series near 0 if not asymptotic: if which != 0: si = mpf_pos(mpf_ci_si_taylor(x, wp, 1), prec, rnd) if which != 1: ci = mpf_ci_si_taylor(x, wp, 0) ci = mpf_add(ci, mpf_euler(wp), wp) ci = mpf_add(ci, mpf_log(mpf_abs(x), wp), prec, rnd) return ci, si x = mpf_abs(x) # Case 2: asymptotic series for x >> 1 xf = to_fixed(x, wp) xr = (MPZ_ONE<<(2*wp)) // xf # 1/x s1 = (MPZ_ONE << wp) s2 = xr t = xr k = 2 while t: t = -t t = (t*xr*k)>>wp k += 1 s1 += t t = (t*xr*k)>>wp k += 1 s2 += t s1 = from_man_exp(s1, -wp) s2 = from_man_exp(s2, -wp) s1 = mpf_div(s1, x, wp) s2 = mpf_div(s2, x, wp) cos, sin = mpf_cos_sin(x, wp) # Ci(x) = sin(x)*s1-cos(x)*s2 # Si(x) = pi/2-cos(x)*s1-sin(x)*s2 if which != 0: si = mpf_add(mpf_mul(cos, s1), mpf_mul(sin, s2), wp) si = mpf_sub(mpf_shift(mpf_pi(wp), -1), si, wp) if sign: si = mpf_neg(si) si = mpf_pos(si, prec, rnd) if which != 1: ci = mpf_sub(mpf_mul(sin, s1), mpf_mul(cos, s2), prec, rnd) return ci, si
def mpi_pi(prec): a = mpf_pi(prec, round_floor) b = mpf_pi(prec, round_ceiling) return a, b
def mpc_zeta(s, prec, rnd=round_fast, alt=0): re, im = s if im == fzero: return mpf_zeta(re, prec, rnd, alt), fzero wp = prec + 20 # Reflection formula. To be rigorous, we should reflect to the left of # re = 1/2 (see comments for mpf_zeta), but this leads to unnecessary # slowdown for interesting values of s if mpf_lt(re, fzero): # XXX: could use the separate refl. formula for Dirichlet eta if alt: q = mpc_sub(mpc_one, mpc_pow(mpc_two, mpc_sub(mpc_one, s, wp), wp), wp) return mpc_mul(mpc_zeta(s, wp), q, prec, rnd) # XXX: -1 should be done exactly y = mpc_sub(mpc_one, s, 10 * wp) a = mpc_gamma(y, wp) b = mpc_zeta(y, wp) c = mpc_sin_pi(mpc_shift(s, -1), wp) rsign, rman, rexp, rbc = re isign, iman, iexp, ibc = im mag = max(rexp + rbc, iexp + ibc) wp2 = wp + mag pi = mpf_pi(wp + wp2) pi2 = (mpf_shift(pi, 1), fzero) d = mpc_div_mpf(mpc_pow(pi2, s, wp2), pi, wp2) return mpc_mul(a, mpc_mul(b, mpc_mul(c, d, wp), wp), prec, rnd) n = int(wp / 2.54 + 5) n += int(0.9 * abs(to_int(im))) d = borwein_coefficients(n) ref = to_fixed(re, wp) imf = to_fixed(im, wp) tre = MP_ZERO tim = MP_ZERO one = MP_ONE << wp one_2wp = MP_ONE << (2 * wp) critical_line = re == fhalf for k in xrange(n): log = log_int_fixed(k + 1, wp) # A square root is much cheaper than an exp if critical_line: w = one_2wp // sqrt_fixed((k + 1) << wp, wp) else: w = to_fixed(mpf_exp(from_man_exp(-ref * log, -2 * wp), wp), wp) if k & 1: w *= (d[n] - d[k]) else: w *= (d[k] - d[n]) wre, wim = cos_sin( from_man_exp(-imf * log_int_fixed(k + 1, wp), -2 * wp), wp) tre += (w * to_fixed(wre, wp)) >> wp tim += (w * to_fixed(wim, wp)) >> wp tre //= (-d[n]) tim //= (-d[n]) tre = from_man_exp(tre, -wp, wp) tim = from_man_exp(tim, -wp, wp) if alt: return mpc_pos((tre, tim), prec, rnd) else: q = mpc_sub(mpc_one, mpc_pow(mpc_two, mpc_sub(mpc_one, s, wp), wp), wp) return mpc_div((tre, tim), q, prec, rnd)
x = mpf_mul(x, mpf_pi(prec), prec) # Shifted an odd multiple of pi ? if nint & 1: c, s = cos_sin(x, prec, negative_rnd[rnd]) return mpf_neg(c), mpf_neg(s) else: return cos_sin(x, prec, rnd) def mpf_cos_pi(x, prec, rnd=round_fast): return mpf_cos_sin_pi(x, prec, rnd)[0] def mpf_sin_pi(x, prec, rnd=round_fast): return mpf_cos_sin_pi(x, prec, rnd)[1] 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)
def mpf_expint(n, x, prec, rnd=round_fast, gamma=False): """ E_n(x), n an integer, x real With gamma=True, computes Gamma(n,x) (upper incomplete gamma function) Returns (real, None) if real, otherwise (real, imag) The imaginary part is an optional branch cut term """ sign, man, exp, bc = x if not man: if gamma: if x == fzero: # Actually gamma function pole if n <= 0: return finf, None return mpf_gamma_int(n, prec, rnd), None if x == finf: return fzero, None # TODO: could return finite imaginary value at -inf return fnan, fnan else: if x == fzero: if n > 1: return from_rational(1, n-1, prec, rnd), None else: return finf, None if x == finf: return fzero, None return fnan, fnan n_orig = n if gamma: n = 1-n wp = prec + 20 xmag = exp + bc # Beware of near-poles if xmag < -10: raise NotImplementedError nmag = bitcount(abs(n)) have_imag = n > 0 and sign negx = mpf_neg(x) # Skip series if direct convergence if n == 0 or 2*nmag - xmag < -wp: if gamma: v = mpf_exp(negx, wp) re = mpf_mul(v, mpf_pow_int(x, n_orig-1, wp), prec, rnd) else: v = mpf_exp(negx, wp) re = mpf_div(v, x, prec, rnd) else: # Finite number of terms, or... can_use_asymptotic_series = -3*wp < n <= 0 # ...large enough? if not can_use_asymptotic_series: xi = abs(to_int(x)) m = min(max(1, xi-n), 2*wp) siz = -n*nmag + (m+n)*bitcount(abs(m+n)) - m*xmag - (144*m//100) tol = -wp-10 can_use_asymptotic_series = siz < tol if can_use_asymptotic_series: r = ((-MPZ_ONE) << (wp+wp)) // to_fixed(x, wp) m = n t = r*m s = MPZ_ONE << wp while m and t: s += t m += 1 t = (m*r*t) >> wp v = mpf_exp(negx, wp) if gamma: # ~ exp(-x) * x^(n-1) * (1 + ...) v = mpf_mul(v, mpf_pow_int(x, n_orig-1, wp), wp) else: # ~ exp(-x)/x * (1 + ...) v = mpf_div(v, x, wp) re = mpf_mul(v, from_man_exp(s, -wp), prec, rnd) elif n == 1: re = mpf_neg(mpf_ei(negx, prec, rnd)) elif n > 0 and n < 3*wp: T1 = mpf_neg(mpf_ei(negx, wp)) if gamma: if n_orig & 1: T1 = mpf_neg(T1) else: T1 = mpf_mul(T1, mpf_pow_int(negx, n-1, wp), wp) r = t = to_fixed(x, wp) facs = [1] * (n-1) for k in range(1,n-1): facs[k] = facs[k-1] * k facs = facs[::-1] s = facs[0] << wp for k in range(1, n-1): if k & 1: s -= facs[k] * t else: s += facs[k] * t t = (t*r) >> wp T2 = from_man_exp(s, -wp, wp) T2 = mpf_mul(T2, mpf_exp(negx, wp)) if gamma: T2 = mpf_mul(T2, mpf_pow_int(x, n_orig, wp), wp) R = mpf_add(T1, T2) re = mpf_div(R, from_int(ifac(n-1)), prec, rnd) else: raise NotImplementedError if have_imag: M = from_int(-ifac(n-1)) if gamma: im = mpf_div(mpf_pi(wp), M, prec, rnd) else: im = mpf_div(mpf_mul(mpf_pi(wp), mpf_pow_int(negx, n_orig-1, wp), wp), M, prec, rnd) return re, im else: return re, None
def mpf_ci_si(x, prec, rnd=round_fast, which=2): """ Calculation of Ci(x), Si(x) for real x. which = 0 -- returns (Ci(x), -) which = 1 -- returns (Si(x), -) which = 2 -- returns (Ci(x), Si(x)) Note: if x < 0, Ci(x) needs an additional imaginary term, pi*i. """ wp = prec + 20 sign, man, exp, bc = x ci, si = None, None if not man: if x == fzero: return (fninf, fzero) if x == fnan: return (x, x) ci = fzero if which != 0: if x == finf: si = mpf_shift(mpf_pi(prec, rnd), -1) if x == fninf: si = mpf_neg(mpf_shift(mpf_pi(prec, negative_rnd[rnd]), -1)) return (ci, si) # For small x: Ci(x) ~ euler + log(x), Si(x) ~ x mag = exp + bc if mag < -wp: if which != 0: si = mpf_perturb(x, 1 - sign, prec, rnd) if which != 1: y = mpf_euler(wp) xabs = mpf_abs(x) ci = mpf_add(y, mpf_log(xabs, wp), prec, rnd) return ci, si # For huge x: Ci(x) ~ sin(x)/x, Si(x) ~ pi/2 elif mag > wp: if which != 0: if sign: si = mpf_neg(mpf_pi(prec, negative_rnd[rnd])) else: si = mpf_pi(prec, rnd) si = mpf_shift(si, -1) if which != 1: ci = mpf_div(mpf_sin(x, wp), x, prec, rnd) return ci, si else: wp += abs(mag) # Use an asymptotic series? The smallest value of n!/x^n # occurs for n ~ x, where the magnitude is ~ exp(-x). asymptotic = mag - 1 > math.log(wp, 2) # Case 1: convergent series near 0 if not asymptotic: if which != 0: si = mpf_pos(mpf_ci_si_taylor(x, wp, 1), prec, rnd) if which != 1: ci = mpf_ci_si_taylor(x, wp, 0) ci = mpf_add(ci, mpf_euler(wp), wp) ci = mpf_add(ci, mpf_log(mpf_abs(x), wp), prec, rnd) return ci, si x = mpf_abs(x) # Case 2: asymptotic series for x >> 1 xf = to_fixed(x, wp) xr = (MP_ONE << (2 * wp)) // xf # 1/x s1 = (MP_ONE << wp) s2 = xr t = xr k = 2 while t: t = -t t = (t * xr * k) >> wp k += 1 s1 += t t = (t * xr * k) >> wp k += 1 s2 += t s1 = from_man_exp(s1, -wp) s2 = from_man_exp(s2, -wp) s1 = mpf_div(s1, x, wp) s2 = mpf_div(s2, x, wp) cos, sin = cos_sin(x, wp) # Ci(x) = sin(x)*s1-cos(x)*s2 # Si(x) = pi/2-cos(x)*s1-sin(x)*s2 if which != 0: si = mpf_add(mpf_mul(cos, s1), mpf_mul(sin, s2), wp) si = mpf_sub(mpf_shift(mpf_pi(wp), -1), si, wp) if sign: si = mpf_neg(si) si = mpf_pos(si, prec, rnd) if which != 1: ci = mpf_sub(mpf_mul(sin, s1), mpf_mul(cos, s2), prec, rnd) return ci, si
def mpf_expint(n, x, prec, rnd=round_fast, gamma=False): """ E_n(x), n an integer, x real With gamma=True, computes Gamma(n,x) (upper incomplete gamma function) Returns (real, None) if real, otherwise (real, imag) The imaginary part is an optional branch cut term """ sign, man, exp, bc = x if not man: if gamma: if x == fzero: # Actually gamma function pole if n <= 0: return finf return mpf_gamma_int(n, prec, rnd) if x == finf: return fzero, None # TODO: could return finite imaginary value at -inf return fnan, fnan else: if x == fzero: if n > 1: return from_rational(1, n - 1, prec, rnd), None else: return finf, None if x == finf: return fzero, None return fnan, fnan n_orig = n if gamma: n = 1 - n wp = prec + 20 xmag = exp + bc # Beware of near-poles if xmag < -10: raise NotImplementedError nmag = bitcount(abs(n)) have_imag = n > 0 and sign negx = mpf_neg(x) # Skip series if direct convergence if n == 0 or 2 * nmag - xmag < -wp: if gamma: v = mpf_exp(negx, wp) re = mpf_mul(v, mpf_pow_int(x, n_orig - 1, wp), prec, rnd) else: v = mpf_exp(negx, wp) re = mpf_div(v, x, prec, rnd) else: # Finite number of terms, or... can_use_asymptotic_series = -3 * wp < n <= 0 # ...large enough? if not can_use_asymptotic_series: xi = abs(to_int(x)) m = min(max(1, xi - n), 2 * wp) siz = -n * nmag + (m + n) * bitcount(abs(m + n)) - m * xmag - ( 144 * m // 100) tol = -wp - 10 can_use_asymptotic_series = siz < tol if can_use_asymptotic_series: r = ((-MP_ONE) << (wp + wp)) // to_fixed(x, wp) m = n t = r * m s = MP_ONE << wp while m and t: s += t m += 1 t = (m * r * t) >> wp v = mpf_exp(negx, wp) if gamma: # ~ exp(-x) * x^(n-1) * (1 + ...) v = mpf_mul(v, mpf_pow_int(x, n_orig - 1, wp), wp) else: # ~ exp(-x)/x * (1 + ...) v = mpf_div(v, x, wp) re = mpf_mul(v, from_man_exp(s, -wp), prec, rnd) elif n == 1: re = mpf_neg(mpf_ei(negx, prec, rnd)) elif n > 0 and n < 3 * wp: T1 = mpf_neg(mpf_ei(negx, wp)) if gamma: if n_orig & 1: T1 = mpf_neg(T1) else: T1 = mpf_mul(T1, mpf_pow_int(negx, n - 1, wp), wp) r = t = to_fixed(x, wp) facs = [1] * (n - 1) for k in range(1, n - 1): facs[k] = facs[k - 1] * k facs = facs[::-1] s = facs[0] << wp for k in range(1, n - 1): if k & 1: s -= facs[k] * t else: s += facs[k] * t t = (t * r) >> wp T2 = from_man_exp(s, -wp, wp) T2 = mpf_mul(T2, mpf_exp(negx, wp)) if gamma: T2 = mpf_mul(T2, mpf_pow_int(x, n_orig, wp), wp) R = mpf_add(T1, T2) re = mpf_div(R, from_int(int_fac(n - 1)), prec, rnd) else: raise NotImplementedError if have_imag: M = from_int(-int_fac(n - 1)) if gamma: im = mpf_div(mpf_pi(wp), M, prec, rnd) else: im = mpf_div( mpf_mul(mpf_pi(wp), mpf_pow_int(negx, n_orig - 1, wp), wp), M, prec, rnd) return re, im else: return re, None
def mpc_ei(z, prec, rnd=round_fast, e1=False): if e1: z = mpc_neg(z) a, b = z asign, aman, aexp, abc = a bsign, bman, bexp, bbc = b if b == fzero: if e1: x = mpf_neg(mpf_ei(a, prec, rnd)) if not asign: y = mpf_neg(mpf_pi(prec, rnd)) else: y = fzero return x, y else: return mpf_ei(a, prec, rnd), fzero if a != fzero: if not aman or not bman: return (fnan, fnan) wp = prec + 40 amag = aexp + abc bmag = bexp + bbc zmag = max(amag, bmag) can_use_asymp = zmag > wp if not can_use_asymp: zabsint = abs(to_int(a)) + abs(to_int(b)) can_use_asymp = zabsint > int(wp * 0.693) + 20 try: if can_use_asymp: if zmag > wp: v = fone, fzero else: zre = to_fixed(a, wp) zim = to_fixed(b, wp) vre, vim = complex_ei_asymptotic(zre, zim, wp) v = from_man_exp(vre, -wp), from_man_exp(vim, -wp) v = mpc_mul(v, mpc_exp(z, wp), wp) v = mpc_div(v, z, wp) if e1: v = mpc_neg(v, prec, rnd) else: x, y = v if bsign: v = mpf_pos(x, prec, rnd), mpf_sub(y, mpf_pi(wp), prec, rnd) else: v = mpf_pos(x, prec, rnd), mpf_add(y, mpf_pi(wp), prec, rnd) return v except NoConvergence: pass #wp += 2*max(0,zmag) wp += 2 * int(to_int(mpc_abs(z, 5))) zre = to_fixed(a, wp) zim = to_fixed(b, wp) vre, vim = complex_ei_taylor(zre, zim, wp) vre += euler_fixed(wp) v = from_man_exp(vre, -wp), from_man_exp(vim, -wp) if e1: u = mpc_log(mpc_neg(z), wp) else: u = mpc_log(z, wp) v = mpc_add(v, u, prec, rnd) if e1: v = mpc_neg(v) return v
def mpf_zeta(s, prec, rnd=round_fast, alt=0): sign, man, exp, bc = s if not man: if s == fzero: if alt: return fhalf else: return mpf_neg(fhalf) if s == finf: return fone return fnan wp = prec + 20 # First term vanishes? if (not sign) and (exp + bc > (math.log(wp, 2) + 2)): return mpf_perturb(fone, alt, prec, rnd) # Optimize for integer arguments elif exp >= 0: if alt: if s == fone: return mpf_ln2(prec, rnd) z = mpf_zeta_int(to_int(s), wp, negative_rnd[rnd]) q = mpf_sub(fone, mpf_pow(ftwo, mpf_sub(fone, s, wp), wp), wp) return mpf_mul(z, q, prec, rnd) else: return mpf_zeta_int(to_int(s), prec, rnd) # Negative: use the reflection formula # Borwein only proves the accuracy bound for x >= 1/2. However, based on # tests, the accuracy without reflection is quite good even some distance # to the left of 1/2. XXX: verify this. if sign: # XXX: could use the separate refl. formula for Dirichlet eta if alt: q = mpf_sub(fone, mpf_pow(ftwo, mpf_sub(fone, s, wp), wp), wp) return mpf_mul(mpf_zeta(s, wp), q, prec, rnd) # XXX: -1 should be done exactly y = mpf_sub(fone, s, 10 * wp) a = mpf_gamma(y, wp) b = mpf_zeta(y, wp) c = mpf_sin_pi(mpf_shift(s, -1), wp) wp2 = wp + (exp + bc) pi = mpf_pi(wp + wp2) d = mpf_div(mpf_pow(mpf_shift(pi, 1), s, wp2), pi, wp2) return mpf_mul(a, mpf_mul(b, mpf_mul(c, d, wp), wp), prec, rnd) t = MP_ZERO #wp += 16 - (prec & 15) # Use Borwein's algorithm n = int(wp / 2.54 + 5) d = borwein_coefficients(n) t = MP_ZERO sf = to_fixed(s, wp) for k in xrange(n): u = from_man_exp(-sf * log_int_fixed(k + 1, wp), -2 * wp, wp) esign, eman, eexp, ebc = mpf_exp(u, wp) offset = eexp + wp if offset >= 0: w = ((d[k] - d[n]) * eman) << offset else: w = ((d[k] - d[n]) * eman) >> (-offset) if k & 1: t -= w else: t += w t = t // (-d[n]) t = from_man_exp(t, -wp, wp) if alt: return mpf_pos(t, prec, rnd) else: q = mpf_sub(fone, mpf_pow(ftwo, mpf_sub(fone, s, wp), wp), wp) return mpf_div(t, q, prec, rnd)
def mpc_ei(z, prec, rnd=round_fast, e1=False): if e1: z = mpc_neg(z) a, b = z asign, aman, aexp, abc = a bsign, bman, bexp, bbc = b if b == fzero: if e1: x = mpf_neg(mpf_ei(a, prec, rnd)) if not asign: y = mpf_neg(mpf_pi(prec, rnd)) else: y = fzero return x, y else: return mpf_ei(a, prec, rnd), fzero if a != fzero: if not aman or not bman: return (fnan, fnan) wp = prec + 40 amag = aexp+abc bmag = bexp+bbc zmag = max(amag, bmag) can_use_asymp = zmag > wp if not can_use_asymp: zabsint = abs(to_int(a)) + abs(to_int(b)) can_use_asymp = zabsint > int(wp*0.693) + 20 try: if can_use_asymp: if zmag > wp: v = fone, fzero else: zre = to_fixed(a, wp) zim = to_fixed(b, wp) vre, vim = complex_ei_asymptotic(zre, zim, wp) v = from_man_exp(vre, -wp), from_man_exp(vim, -wp) v = mpc_mul(v, mpc_exp(z, wp), wp) v = mpc_div(v, z, wp) if e1: v = mpc_neg(v, prec, rnd) else: x, y = v if bsign: v = mpf_pos(x, prec, rnd), mpf_sub(y, mpf_pi(wp), prec, rnd) else: v = mpf_pos(x, prec, rnd), mpf_add(y, mpf_pi(wp), prec, rnd) return v except NoConvergence: pass #wp += 2*max(0,zmag) wp += 2*int(to_int(mpc_abs(z, 5))) zre = to_fixed(a, wp) zim = to_fixed(b, wp) vre, vim = complex_ei_taylor(zre, zim, wp) vre += euler_fixed(wp) v = from_man_exp(vre,-wp), from_man_exp(vim,-wp) if e1: u = mpc_log(mpc_neg(z),wp) else: u = mpc_log(z,wp) v = mpc_add(v, u, prec, rnd) if e1: v = mpc_neg(v) return v
def mpc_zeta(s, prec, rnd=round_fast, alt=0, force=False): re, im = s if im == fzero: return mpf_zeta(re, prec, rnd, alt), fzero # slow for large s if (not force) and mpf_gt(mpc_abs(s, 10), from_int(prec)): raise NotImplementedError wp = prec + 20 # Near pole r = mpc_sub(mpc_one, s, wp) asign, aman, aexp, abc = mpc_abs(r, 10) pole_dist = -2 * (aexp + abc) if pole_dist > wp: if alt: q = mpf_ln2(wp) y = mpf_mul(q, mpf_euler(wp), wp) g = mpf_shift(mpf_mul(q, q, wp), -1) g = mpf_sub(y, g) z = mpc_mul_mpf(r, mpf_neg(g), wp) z = mpc_add_mpf(z, q, wp) return mpc_pos(z, prec, rnd) else: q = mpc_neg(mpc_div(mpc_one, r, wp)) q = mpc_add_mpf(q, mpf_euler(wp), wp) return mpc_pos(q, prec, rnd) else: wp += max(0, pole_dist) # Reflection formula. To be rigorous, we should reflect to the left of # re = 1/2 (see comments for mpf_zeta), but this leads to unnecessary # slowdown for interesting values of s if mpf_lt(re, fzero): # XXX: could use the separate refl. formula for Dirichlet eta if alt: q = mpc_sub(mpc_one, mpc_pow(mpc_two, mpc_sub(mpc_one, s, wp), wp), wp) return mpc_mul(mpc_zeta(s, wp), q, prec, rnd) # XXX: -1 should be done exactly y = mpc_sub(mpc_one, s, 10 * wp) a = mpc_gamma(y, wp) b = mpc_zeta(y, wp) c = mpc_sin_pi(mpc_shift(s, -1), wp) rsign, rman, rexp, rbc = re isign, iman, iexp, ibc = im mag = max(rexp + rbc, iexp + ibc) wp2 = wp + mag pi = mpf_pi(wp + wp2) pi2 = (mpf_shift(pi, 1), fzero) d = mpc_div_mpf(mpc_pow(pi2, s, wp2), pi, wp2) return mpc_mul(a, mpc_mul(b, mpc_mul(c, d, wp), wp), prec, rnd) n = int(wp / 2.54 + 5) n += int(0.9 * abs(to_int(im))) d = borwein_coefficients(n) ref = to_fixed(re, wp) imf = to_fixed(im, wp) tre = MPZ_ZERO tim = MPZ_ZERO one = MPZ_ONE << wp one_2wp = MPZ_ONE << (2 * wp) critical_line = re == fhalf for k in xrange(n): log = log_int_fixed(k + 1, wp) # A square root is much cheaper than an exp if critical_line: w = one_2wp // sqrt_fixed((k + 1) << wp, wp) else: w = to_fixed(mpf_exp(from_man_exp(-ref * log, -2 * wp), wp), wp) if k & 1: w *= (d[n] - d[k]) else: w *= (d[k] - d[n]) wre, wim = mpf_cos_sin(from_man_exp(-imf * log, -2 * wp), wp) tre += (w * to_fixed(wre, wp)) >> wp tim += (w * to_fixed(wim, wp)) >> wp tre //= (-d[n]) tim //= (-d[n]) tre = from_man_exp(tre, -wp, wp) tim = from_man_exp(tim, -wp, wp) if alt: return mpc_pos((tre, tim), prec, rnd) else: q = mpc_sub(mpc_one, mpc_pow(mpc_two, r, wp), wp) return mpc_div((tre, tim), q, prec, rnd)
c, s = cos_sin(x, prec, negative_rnd[rnd]) return mpf_neg(c), mpf_neg(s) else: return cos_sin(x, prec, rnd) def mpf_cos_pi(x, prec, rnd=round_fast): return mpf_cos_sin_pi(x, prec, rnd)[0] def mpf_sin_pi(x, prec, rnd=round_fast): return mpf_cos_sin_pi(x, prec, rnd)[1] 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