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_asin(x, prec, rnd=round_fast): sign, man, exp, bc = x if bc+exp > 0 and x not in (fone, fnone): raise ComplexResult("asin(x) is real only for -1 <= x <= 1") flag_nr = True if prec < 1000 or exp+bc < -13: flag_nr = False else: ebc = exp + bc if ebc < -13: flag_nr = False elif ebc < -3: if prec < 3000: flag_nr = False if not flag_nr: # asin(x) = 2*atan(x/(1+sqrt(1-x**2))) wp = prec + 15 a = mpf_mul(x, x) b = mpf_add(fone, mpf_sqrt(mpf_sub(fone, a, wp), wp), wp) c = mpf_div(x, b, wp) return mpf_shift(mpf_atan(c, prec, rnd), 1) # use Newton's method extra = 10 extra_p = 10 prec2 = prec + extra r = math.asin(to_float(x)) r = from_float(r, 50, rnd) for p in giant_steps(50, prec2): wp = p + extra_p c, s = cos_sin(r, wp, rnd) tmp = mpf_sub(x, s, wp, rnd) tmp = mpf_div(tmp, c, wp, rnd) r = mpf_add(r, tmp, wp, rnd) sign, man, exp, bc = r return normalize(sign, man, exp, bc, 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 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 mpi_sub(s, t, prec): sa, sb = s ta, tb = t a = mpf_sub(sa, tb, prec, round_floor) b = mpf_sub(sb, ta, prec, round_ceiling) if a == fnan: a = fninf if b == fnan: b = finf return a, b
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 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 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 twinprime_fixed(prec): def I(n): return sum( moebius(d) << (n // d) for d in xrange(1, n + 1) if not n % d) // n wp = 2 * prec + 30 res = fone primes = [from_rational(1, p, wp) for p in [2, 3, 5, 7]] ppowers = [mpf_mul(p, p, wp) for p in primes] n = 2 while 1: a = mpf_zeta_int(n, wp) for i in range(4): a = mpf_mul(a, mpf_sub(fone, ppowers[i]), wp) ppowers[i] = mpf_mul(ppowers[i], primes[i], wp) a = mpf_pow_int(a, -I(n), wp) if mpf_pos(a, prec + 10, 'n') == fone: break #from libmpf import to_str #print n, to_str(mpf_sub(fone, a), 6) res = mpf_mul(res, a, wp) n += 1 res = mpf_mul(res, from_int(3 * 15 * 35), wp) res = mpf_div(res, from_int(4 * 16 * 36), wp) return to_fixed(res, prec)
def mpc_sqrt(z, prec, rnd=round_fast): """Complex square root (principal branch). We have sqrt(a+bi) = sqrt((r+a)/2) + b/sqrt(2*(r+a))*i where r = abs(a+bi), when a+bi is not a negative real number.""" a, b = z if b == fzero: if a == fzero: return (a, b) # When a+bi is a negative real number, we get a real sqrt times i if a[0]: im = mpf_sqrt(mpf_neg(a), prec, rnd) return (fzero, im) else: re = mpf_sqrt(a, prec, rnd) return (re, fzero) wp = prec+20 if not a[0]: # case a positive t = mpf_add(mpc_abs((a, b), wp), a, wp) # t = abs(a+bi) + a u = mpf_shift(t, -1) # u = t/2 re = mpf_sqrt(u, prec, rnd) # re = sqrt(u) v = mpf_shift(t, 1) # v = 2*t w = mpf_sqrt(v, wp) # w = sqrt(v) im = mpf_div(b, w, prec, rnd) # im = b / w else: # case a negative t = mpf_sub(mpc_abs((a, b), wp), a, wp) # t = abs(a+bi) - a u = mpf_shift(t, -1) # u = t/2 im = mpf_sqrt(u, prec, rnd) # im = sqrt(u) v = mpf_shift(t, 1) # v = 2*t w = mpf_sqrt(v, wp) # w = sqrt(v) re = mpf_div(b, w, prec, rnd) # re = b/w if b[0]: re = mpf_neg(re) im = mpf_neg(im) return re, im
def mpc_sqrt(z, prec, rnd=round_fast): """Complex square root (principal branch). We have sqrt(a+bi) = sqrt((r+a)/2) + b/sqrt(2*(r+a))*i where r = abs(a+bi), when a+bi is not a negative real number.""" a, b = z if b == fzero: if a == fzero: return (a, b) # When a+bi is a negative real number, we get a real sqrt times i if a[0]: im = mpf_sqrt(mpf_neg(a), prec, rnd) return (fzero, im) else: re = mpf_sqrt(a, prec, rnd) return (re, fzero) wp = prec + 20 if not a[0]: # case a positive t = mpf_add(mpc_abs((a, b), wp), a, wp) # t = abs(a+bi) + a u = mpf_shift(t, -1) # u = t/2 re = mpf_sqrt(u, prec, rnd) # re = sqrt(u) v = mpf_shift(t, 1) # v = 2*t w = mpf_sqrt(v, wp) # w = sqrt(v) im = mpf_div(b, w, prec, rnd) # im = b / w else: # case a negative t = mpf_sub(mpc_abs((a, b), wp), a, wp) # t = abs(a+bi) - a u = mpf_shift(t, -1) # u = t/2 im = mpf_sqrt(u, prec, rnd) # im = sqrt(u) v = mpf_shift(t, 1) # v = 2*t w = mpf_sqrt(v, wp) # w = sqrt(v) re = mpf_div(b, w, prec, rnd) # re = b/w if b[0]: re = mpf_neg(re) im = mpf_neg(im) return re, im
def __rsub__(s, t): prec, rounding = prec_rounding if type(t) in int_types: return make_mpf(mpf_sub(from_int(t), s._mpf_, prec, rounding)) t = mpf_convert_lhs(t) if t is NotImplemented: return t return t - s
def cosh_sinh(x, prec, rnd=round_fast, tanh=0): """Simultaneously compute (cosh(x), sinh(x)) for real x""" sign, man, exp, bc = x if (not man) and exp: if tanh: if x == finf: return fone if x == fninf: return fnone return fnan if x == finf: return (finf, finf) if x == fninf: return (finf, fninf) return fnan, fnan if sign: man = -man mag = exp + bc prec2 = prec + 20 if mag < -3: # Extremely close to 0, sinh(x) ~= x and cosh(x) ~= 1 if mag < -prec-2: if tanh: return mpf_perturb(x, 1-sign, prec, rnd) cosh = mpf_perturb(fone, 0, prec, rnd) sinh = mpf_perturb(x, sign, prec, rnd) return cosh, sinh # Avoid cancellation when computing sinh # TODO: might be faster to use sinh series directly prec2 += (-mag) + 4 # In the general case, we use # cosh(x) = (exp(x) + exp(-x))/2 # sinh(x) = (exp(x) - exp(-x))/2 # and note that the exponential only needs to be computed once. ep = mpf_exp(x, prec2) em = mpf_div(fone, ep, prec2) if tanh: ch = mpf_add(ep, em, prec2, rnd) sh = mpf_sub(ep, em, prec2, rnd) return mpf_div(sh, ch, prec, rnd) else: ch = mpf_shift(mpf_add(ep, em, prec, rnd), -1) sh = mpf_shift(mpf_sub(ep, em, prec, rnd), -1) return ch, sh
def mpc_square(z, prec, rnd=round_fast): # (a+b*I)**2 == a**2 - b**2 + 2*I*a*b a, b = z p = mpf_mul(a,a) q = mpf_mul(b,b) r = mpf_mul(a,b, prec, rnd) re = mpf_sub(p, q, prec, rnd) im = mpf_shift(r, 1) return re, im
def mpc_square(z, prec, rnd=round_fast): # (a+b*I)**2 == a**2 - b**2 + 2*I*a*b a, b = z p = mpf_mul(a, a) q = mpf_mul(b, b) r = mpf_mul(a, b, prec, rnd) re = mpf_sub(p, q, prec, rnd) im = mpf_shift(r, 1) return re, im
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_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 mpc_div(z, w, prec, rnd=round_fast): a, b = z c, d = w wp = prec + 10 # mag = c*c + d*d mag = mpf_add(mpf_mul(c, c), mpf_mul(d, d), wp) # (a*c+b*d)/mag, (b*c-a*d)/mag t = mpf_add(mpf_mul(a, c), mpf_mul(b, d), wp) u = mpf_sub(mpf_mul(b, c), mpf_mul(a, d), wp) return mpf_div(t, mag, prec, rnd), mpf_div(u, mag, prec, rnd)
def mpf_asin(x, prec, rnd=round_fast): sign, man, exp, bc = x if bc + exp > 0 and x not in (fone, fnone): raise ComplexResult("asin(x) is real only for -1 <= x <= 1") # asin(x) = 2*atan(x/(1+sqrt(1-x**2))) wp = prec + 15 a = mpf_mul(x, x) b = mpf_add(fone, mpf_sqrt(mpf_sub(fone, a, wp), wp), wp) c = mpf_div(x, b, wp) return mpf_shift(mpf_atan(c, prec, rnd), 1)
def mpf_atanh(x, prec, rnd=round_fast): # atanh(x) = log((1+x)/(1-x))/2 sign, man, exp, bc = x mag = bc + exp if mag > 0: raise ComplexResult("atanh(x) is real only for -1 < x < 1") wp = prec + 15 a = mpf_add(x, fone, wp) b = mpf_sub(fone, x, wp) return mpf_shift(mpf_log(mpf_div(a, b, wp), prec, rnd), -1)
def mpc_div(z, w, prec, rnd=round_fast): a, b = z c, d = w wp = prec + 10 # mag = c*c + d*d mag = mpf_add(mpf_mul(c, c), mpf_mul(d, d), wp) # (a*c+b*d)/mag, (b*c-a*d)/mag t = mpf_add(mpf_mul(a,c), mpf_mul(b,d), wp) u = mpf_sub(mpf_mul(b,c), mpf_mul(a,d), wp) return mpf_div(t,mag,prec,rnd), mpf_div(u,mag,prec,rnd)
def mpf_zeta_int(s, prec, rnd=round_fast): """ Optimized computation of zeta(s) for an integer s. """ wp = prec + 20 s = int(s) if s in zeta_int_cache and zeta_int_cache[s][0] >= wp: return mpf_pos(zeta_int_cache[s][1], prec, rnd) if s < 2: if s == 1: raise ValueError("zeta(1) pole") if not s: return mpf_neg(fhalf) return mpf_div(mpf_bernoulli(-s + 1, wp), from_int(s - 1), prec, rnd) # 2^-s term vanishes? if s >= wp: return mpf_perturb(fone, 0, prec, rnd) # 5^-s term vanishes? elif s >= wp * 0.431: t = one = 1 << wp t += 1 << (wp - s) t += one // (MPZ_THREE**s) t += 1 << max(0, wp - s * 2) return from_man_exp(t, -wp, prec, rnd) else: # Fast enough to sum directly? # Even better, we use the Euler product (idea stolen from pari) m = (float(wp) / (s - 1) + 1) if m < 30: needed_terms = int(2.0**m + 1) if needed_terms < int(wp / 2.54 + 5) / 10: t = fone for k in list_primes(needed_terms): #print k, needed_terms powprec = int(wp - s * math.log(k, 2)) if powprec < 2: break a = mpf_sub(fone, mpf_pow_int(from_int(k), -s, powprec), wp) t = mpf_mul(t, a, wp) return mpf_div(fone, t, wp) # Use Borwein's algorithm n = int(wp / 2.54 + 5) d = borwein_coefficients(n) t = MPZ_ZERO s = MPZ(s) for k in xrange(n): t += (((-1)**k * (d[k] - d[n])) << wp) // (k + 1)**s t = (t << wp) // (-d[n]) t = (t << wp) // ((1 << wp) - (1 << (wp + 1 - s))) if (s in zeta_int_cache and zeta_int_cache[s][0] < wp) or (s not in zeta_int_cache): zeta_int_cache[s] = (wp, from_man_exp(t, -wp - wp)) return from_man_exp(t, -wp - wp, 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_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 mpf_erfc(x, prec, rnd=round_fast): sign, man, exp, bc = x if not man: if x == fzero: return fone if x == finf: return fzero if x == fninf: return ftwo return fnan wp = prec + 20 mag = bc + exp # Preserve full accuracy when exponent grows huge wp += max(0, 2 * mag) regular_erf = sign or mag < 2 if regular_erf or not erfc_check_series(x, wp): if regular_erf: return mpf_sub(fone, mpf_erf(x, prec + 10, negative_rnd[rnd]), prec, rnd) # 1-erf(x) ~ exp(-x^2), increase prec to deal with cancellation n = to_int(x) return mpf_sub(fone, mpf_erf(x, prec + int(n**2 * 1.44) + 10), prec, rnd) s = term = MP_ONE << wp term_prev = 0 t = (2 * to_fixed(x, wp)**2) >> wp k = 1 while 1: term = ((term * (2 * k - 1)) << wp) // t if k > 4 and term > term_prev or not term: break if k & 1: s -= term else: s += term term_prev = term #print k, to_str(from_man_exp(term, -wp, 50), 10) k += 1 s = (s << wp) // sqrt_fixed(pi_fixed(wp), wp) s = from_man_exp(s, -wp, wp) z = mpf_exp(mpf_neg(mpf_mul(x, x, wp), wp), wp) y = mpf_div(mpf_mul(z, s, wp), x, prec, rnd) return y
def mpf_zeta_int(s, prec, rnd=round_fast): """ Optimized computation of zeta(s) for an integer s. """ wp = prec + 20 s = int(s) if s in zeta_int_cache and zeta_int_cache[s][0] >= wp: return mpf_pos(zeta_int_cache[s][1], prec, rnd) if s < 2: if s == 1: raise ValueError("zeta(1) pole") if not s: return mpf_neg(fhalf) return mpf_div(mpf_bernoulli(-s+1, wp), from_int(s-1), prec, rnd) # 2^-s term vanishes? if s >= wp: return mpf_perturb(fone, 0, prec, rnd) # 5^-s term vanishes? elif s >= wp*0.431: t = one = 1 << wp t += 1 << (wp - s) t += one // (MPZ_THREE ** s) t += 1 << max(0, wp - s*2) return from_man_exp(t, -wp, prec, rnd) else: # Fast enough to sum directly? # Even better, we use the Euler product (idea stolen from pari) m = (float(wp)/(s-1) + 1) if m < 30: needed_terms = int(2.0**m + 1) if needed_terms < int(wp/2.54 + 5) / 10: t = fone for k in list_primes(needed_terms): #print k, needed_terms powprec = int(wp - s*math.log(k,2)) if powprec < 2: break a = mpf_sub(fone, mpf_pow_int(from_int(k), -s, powprec), wp) t = mpf_mul(t, a, wp) return mpf_div(fone, t, wp) # Use Borwein's algorithm n = int(wp/2.54 + 5) d = borwein_coefficients(n) t = MPZ_ZERO s = MPZ(s) for k in xrange(n): t += (((-1)**k * (d[k] - d[n])) << wp) // (k+1)**s t = (t << wp) // (-d[n]) t = (t << wp) // ((1 << wp) - (1 << (wp+1-s))) if (s in zeta_int_cache and zeta_int_cache[s][0] < wp) or (s not in zeta_int_cache): zeta_int_cache[s] = (wp, from_man_exp(t, -wp-wp)) return from_man_exp(t, -wp-wp, prec, rnd)
def mpi_from_str_a_b(x, y, percent, prec): wp = prec + 20 xa = from_str(x, wp, round_floor) xb = from_str(x, wp, round_ceiling) #ya = from_str(y, wp, round_floor) y = from_str(y, wp, round_ceiling) assert mpf_ge(y, fzero) if percent: y = mpf_mul(MAX(mpf_abs(xa), mpf_abs(xb)), y, wp, round_ceiling) y = mpf_div(y, from_int(100), wp, round_ceiling) a = mpf_sub(xa, y, prec, round_floor) b = mpf_add(xb, y, prec, round_ceiling) return a, b
def mpf_acos(x, prec, rnd=round_fast): # acos(x) = 2*atan(sqrt(1-x**2)/(1+x)) sign, man, exp, bc = x if bc + exp > 0: if x not in (fone, fnone): raise ComplexResult("acos(x) is real only for -1 <= x <= 1") if x == fnone: return mpf_pi(prec, rnd) wp = prec + 15 a = mpf_mul(x, x) b = mpf_sqrt(mpf_sub(fone, a, wp), wp) c = mpf_div(b, mpf_add(fone, x, wp), wp) return mpf_shift(mpf_atan(c, prec, rnd), 1)
def mpf_erfc(x, prec, rnd=round_fast): sign, man, exp, bc = x if not man: if x == fzero: return fone if x == finf: return fzero if x == fninf: return ftwo return fnan wp = prec + 20 mag = bc+exp # Preserve full accuracy when exponent grows huge wp += max(0, 2*mag) regular_erf = sign or mag < 2 if regular_erf or not erfc_check_series(x, wp): if regular_erf: return mpf_sub(fone, mpf_erf(x, prec+10, negative_rnd[rnd]), prec, rnd) # 1-erf(x) ~ exp(-x^2), increase prec to deal with cancellation n = to_int(x)+1 return mpf_sub(fone, mpf_erf(x, prec + int(n**2*1.44) + 10), prec, rnd) s = term = MPZ_ONE << wp term_prev = 0 t = (2 * to_fixed(x, wp) ** 2) >> wp k = 1 while 1: term = ((term * (2*k - 1)) << wp) // t if k > 4 and term > term_prev or not term: break if k & 1: s -= term else: s += term term_prev = term #print k, to_str(from_man_exp(term, -wp, 50), 10) k += 1 s = (s << wp) // sqrt_fixed(pi_fixed(wp), wp) s = from_man_exp(s, -wp, wp) z = mpf_exp(mpf_neg(mpf_mul(x,x,wp),wp),wp) y = mpf_div(mpf_mul(z, s, wp), x, prec, rnd) return y
def exp_newton(x, prec): extra = 10 r = mpf_exp(x, 60) start = 50 prevp = start for p in giant_steps(start, prec+extra, 4): h = mpf_sub(x, mpf_log(r, p), p) h2 = mpf_mul(h, h, p) h3 = mpf_mul(h2, h, p) h4 = mpf_mul(h2, h2, p) t = mpf_add(h, mpf_shift(h2, -1), p) t = mpf_add(t, mpf_div(h3, from_int(6, p), p), p) t = mpf_add(t, mpf_div(h4, from_int(24, p), p), p) t = mpf_mul(r, t, p) r = mpf_add(r, t, p) return r
def mpc_mul(z, w, prec, rnd=round_fast): """ Complex multiplication. Returns the real and imaginary part of (a+bi)*(c+di), rounded to the specified precision. The rounding mode applies to the real and imaginary parts separately. """ a, b = z c, d = w p = mpf_mul(a, c) q = mpf_mul(b, d) r = mpf_mul(a, d) s = mpf_mul(b, c) re = mpf_sub(p, q, prec, rnd) im = mpf_add(r, s, prec, rnd) return re, im
def mpc_atan(z, prec, rnd=round_fast): a, b = z # atan(z) = (I/2)*(log(1-I*z) - log(1+I*z)) # x = 1-I*z = 1 + b - I*a # y = 1+I*z = 1 - b + I*a wp = prec + 15 x = mpf_add(fone, b, wp), mpf_neg(a) y = mpf_sub(fone, b, wp), a l1 = mpc_log(x, wp) l2 = mpc_log(y, wp) a, b = mpc_sub(l1, l2, prec, rnd) # (I/2) * (a+b*I) = (-b/2 + a/2*I) v = mpf_neg(mpf_shift(b, -1)), mpf_shift(a, -1) # Subtraction at infinity gives correct real part but # wrong imaginary part (should be zero) if v[1] == fnan and mpc_is_inf(z): v = (v[0], fzero) return v
def mpc_atan(z, prec, rnd=round_fast): a, b = z # atan(z) = (I/2)*(log(1-I*z) - log(1+I*z)) # x = 1-I*z = 1 + b - I*a # y = 1+I*z = 1 - b + I*a wp = prec + 15 x = mpf_add(fone, b, wp), mpf_neg(a) y = mpf_sub(fone, b, wp), a l1 = mpc_log(x, wp) l2 = mpc_log(y, wp) a, b = mpc_sub(l1, l2, prec, rnd) # (I/2) * (a+b*I) = (-b/2 + a/2*I) v = mpf_neg(mpf_shift(b,-1)), mpf_shift(a,-1) # Subtraction at infinity gives correct real part but # wrong imaginary part (should be zero) if v[1] == fnan and mpc_is_inf(z): v = (v[0], fzero) return v
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 mpf_atanh(x, prec, rnd=round_fast): # atanh(x) = log((1+x)/(1-x))/2 sign, man, exp, bc = x if (not man) and exp: if x in (fzero, fnan): return x raise ComplexResult("atanh(x) is real only for -1 <= x <= 1") mag = bc + exp if mag > 0: if mag == 1 and man == 1: return [finf, fninf][sign] raise ComplexResult("atanh(x) is real only for -1 <= x <= 1") wp = prec + 15 if mag < -8: if mag < -wp: return mpf_perturb(x, sign, prec, rnd) wp += (-mag) a = mpf_add(x, fone, wp) b = mpf_sub(fone, x, wp) return mpf_shift(mpf_log(mpf_div(a, b, wp), prec, rnd), -1)
def mpf_fibonacci(x, prec, rnd=round_fast): sign, man, exp, bc = x if not man: if x == fninf: return fnan return x # F(2^n) ~= 2^(2^n) size = abs(exp+bc) if exp >= 0: # Exact if size < 10 or size <= bitcount(prec): return from_int(ifib(to_int(x)), prec, rnd) # Use the modified Binet formula wp = prec + size + 20 a = mpf_phi(wp) b = mpf_add(mpf_shift(a, 1), fnone, wp) u = mpf_pow(a, x, wp) v = mpf_cos_pi(x, wp) v = mpf_div(v, u, wp) u = mpf_sub(u, v, wp) u = mpf_div(u, b, prec, rnd) return u
def twinprime_fixed(prec): def I(n): return sum(moebius(d)<<(n//d) for d in xrange(1,n+1) if not n%d)//n wp = 2*prec + 30 res = fone primes = [from_rational(1,p,wp) for p in [2,3,5,7]] ppowers = [mpf_mul(p,p,wp) for p in primes] n = 2 while 1: a = mpf_zeta_int(n, wp) for i in range(4): a = mpf_mul(a, mpf_sub(fone, ppowers[i]), wp) ppowers[i] = mpf_mul(ppowers[i], primes[i], wp) a = mpf_pow_int(a, -I(n), wp) if mpf_pos(a, prec+10, 'n') == fone: break #from libmpf import to_str #print n, to_str(mpf_sub(fone, a), 6) res = mpf_mul(res, a, wp) n += 1 res = mpf_mul(res, from_int(3*15*35), wp) res = mpf_div(res, from_int(4*16*36), wp) return to_fixed(res, prec)
def mpf_log(x, prec, rnd=round_fast): """ Compute the natural logarithm of the mpf value x. If x is negative, ComplexResult is raised. """ sign, man, exp, bc = x if not man: if x == fzero: return fninf if x == finf: return finf if x == fnan: return fnan if sign: raise ComplexResult("logarithm of a negative number") # log(2^n) if man == 1: if not exp: return fzero return from_man_exp(exp*ln2_fixed(prec+20), -prec-20, prec, rnd) # Assume 20 bits to be sufficient for cancelling rounding errors wp = prec + 20 mag = bc + exp # Already on the standard interval, (0.5, 1) if not mag: t = rshift(man, bc-wp) log2n = 0 # Watch out for "x = 0.9999" # Proceed only if 1-x lost at most 15 bits of accuracy res = (MP_ONE << wp) - t if not (res >> (wp - 15)): # Find out extra precision needed delta = mpf_sub(x, fone, 10) delta_bits = -(delta[2] + delta[3]) # O(x^2) term vanishes relatively if delta_bits > wp + 10: xm1 = mpf_sub(x, fone, prec, rnd) return mpf_perturb(xm1, 1, prec, rnd) else: wp += delta_bits t = rshift(man, bc-wp) # Already on the standard interval, (1, 2) elif mag == 1: t = rshift(man, bc-wp-1) log2n = 0 # Watch out for "x = 1.0001" # Similar to above; note that we flip signs # to obtain a positive residual, ensuring that # the following shift rounds down res = t - (MP_ONE << wp) if not (res >> (wp - 15)): # Find out extra precision needed delta = mpf_sub(x, fone, 10) delta_bits = -(delta[2] + delta[3]) # O(x^2) term vanishes relatively if delta_bits > wp + 10: xm1 = mpf_sub(x, fone, prec, rnd) return mpf_perturb(xm1, 1, prec, rnd) else: wp += delta_bits t = rshift(man, bc-wp-1) # Rescale else: # Estimated precision needed for n*log(2) to # be accurate relatively wp += int(math.log(1+abs(mag),2)) log2n = mag * ln2_fixed(wp) # Rescaled argument as a fixed-point number t = rshift(man, bc-wp) # Use the faster method if wp < LOG_TAYLOR_PREC: a = log_taylor(t, wp) else: a = log_newton(t, wp) return from_man_exp(a + log2n, -wp, prec, rnd)
def mpf_bernoulli(n, prec, rnd=None): """Computation of Bernoulli numbers (numerically)""" if n < 2: if n < 0: raise ValueError("Bernoulli numbers only defined for n >= 0") if n == 0: return fone if n == 1: return mpf_neg(fhalf) # For odd n > 1, the Bernoulli numbers are zero if n & 1: return fzero # If precision is extremely high, we can save time by computing # the Bernoulli number at a lower precision that is sufficient to # obtain the exact fraction, round to the exact fraction, and # convert the fraction back to an mpf value at the original precision if prec > BERNOULLI_PREC_CUTOFF and prec > bernoulli_size(n)*1.1 + 1000: p, q = bernfrac(n) return from_rational(p, q, prec, rnd or round_floor) if n > MAX_BERNOULLI_CACHE: return mpf_bernoulli_huge(n, prec, rnd) wp = prec + 30 # Reuse nearby precisions wp += 32 - (prec & 31) cached = bernoulli_cache.get(wp) if cached: numbers, state = cached if n in numbers: if not rnd: return numbers[n] return mpf_pos(numbers[n], prec, rnd) m, bin, bin1 = state if n - m > 10: return mpf_bernoulli_huge(n, prec, rnd) else: if n > 10: return mpf_bernoulli_huge(n, prec, rnd) numbers = {0:fone} m, bin, bin1 = state = [2, MPZ(10), MPZ_ONE] bernoulli_cache[wp] = (numbers, state) while m <= n: #print m case = m % 6 # Accurately estimate size of B_m so we can use # fixed point math without using too much precision szbm = bernoulli_size(m) s = 0 sexp = max(0, szbm) - wp if m < 6: a = MPZ_ZERO else: a = bin1 for j in xrange(1, m//6+1): usign, uman, uexp, ubc = u = numbers[m-6*j] if usign: uman = -uman s += lshift(a*uman, uexp-sexp) # Update inner binomial coefficient j6 = 6*j a *= ((m-5-j6)*(m-4-j6)*(m-3-j6)*(m-2-j6)*(m-1-j6)*(m-j6)) a //= ((4+j6)*(5+j6)*(6+j6)*(7+j6)*(8+j6)*(9+j6)) if case == 0: b = mpf_rdiv_int(m+3, f3, wp) if case == 2: b = mpf_rdiv_int(m+3, f3, wp) if case == 4: b = mpf_rdiv_int(-m-3, f6, wp) s = from_man_exp(s, sexp, wp) b = mpf_div(mpf_sub(b, s, wp), from_int(bin), wp) numbers[m] = b m += 2 # Update outer binomial coefficient bin = bin * ((m+2)*(m+3)) // (m*(m-1)) if m > 6: bin1 = bin1 * ((2+m)*(3+m)) // ((m-7)*(m-6)) state[:] = [m, bin, bin1] return numbers[n]
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_bernoulli(n, prec, rnd=None): """Computation of Bernoulli numbers (numerically)""" if n < 2: if n < 0: raise ValueError("Bernoulli numbers only defined for n >= 0") if n == 0: return fone if n == 1: return mpf_neg(fhalf) # For odd n > 1, the Bernoulli numbers are zero if n & 1: return fzero # If precision is extremely high, we can save time by computing # the Bernoulli number at a lower precision that is sufficient to # obtain the exact fraction, round to the exact fraction, and # convert the fraction back to an mpf value at the original precision if prec > BERNOULLI_PREC_CUTOFF and prec > bernoulli_size(n) * 1.1 + 1000: p, q = bernfrac(n) return from_rational(p, q, prec, rnd or round_floor) if n > MAX_BERNOULLI_CACHE: return mpf_bernoulli_huge(n, prec, rnd) wp = prec + 30 # Reuse nearby precisions wp += 32 - (prec & 31) cached = bernoulli_cache.get(wp) if cached: numbers, state = cached if n in numbers: if not rnd: return numbers[n] return mpf_pos(numbers[n], prec, rnd) m, bin, bin1 = state if n - m > 10: return mpf_bernoulli_huge(n, prec, rnd) else: if n > 10: return mpf_bernoulli_huge(n, prec, rnd) numbers = {0: fone} m, bin, bin1 = state = [2, MP_BASE(10), MP_ONE] bernoulli_cache[wp] = (numbers, state) while m <= n: #print m case = m % 6 # Accurately estimate size of B_m so we can use # fixed point math without using too much precision szbm = bernoulli_size(m) s = 0 sexp = max(0, szbm) - wp if m < 6: a = MP_ZERO else: a = bin1 for j in xrange(1, m // 6 + 1): usign, uman, uexp, ubc = u = numbers[m - 6 * j] if usign: uman = -uman s += lshift(a * uman, uexp - sexp) # Update inner binomial coefficient j6 = 6 * j a *= ((m - 5 - j6) * (m - 4 - j6) * (m - 3 - j6) * (m - 2 - j6) * (m - 1 - j6) * (m - j6)) a //= ((4 + j6) * (5 + j6) * (6 + j6) * (7 + j6) * (8 + j6) * (9 + j6)) if case == 0: b = mpf_rdiv_int(m + 3, f3, wp) if case == 2: b = mpf_rdiv_int(m + 3, f3, wp) if case == 4: b = mpf_rdiv_int(-m - 3, f6, wp) s = from_man_exp(s, sexp, wp) b = mpf_div(mpf_sub(b, s, wp), from_int(bin), wp) numbers[m] = b m += 2 # Update outer binomial coefficient bin = bin * ((m + 2) * (m + 3)) // (m * (m - 1)) if m > 6: bin1 = bin1 * ((2 + m) * (3 + m)) // ((m - 7) * (m - 6)) state[:] = [m, bin, bin1]
if im[0]: return rs + " - " + to_str(mpf_neg(im), dps) + "j" else: return rs + " + " + to_str(im, dps) + "j" def mpc_add((a, b), (c, d), prec, rnd=round_fast): return mpf_add(a, c, prec, rnd), mpf_add(b, d, prec, rnd) def mpc_add_mpf((a, b), p, prec, rnd=round_fast): return mpf_add(a, p, prec, rnd), b def mpc_sub((a, b), (c, d), prec, rnd=round_fast): return mpf_sub(a, c, prec, rnd), mpf_sub(b, d, prec, rnd) def mpc_sub_mpf((a, b), p, prec, rnd=round_fast): return mpf_sub(a, p, prec, rnd), b def mpc_pos((a, b), prec, rnd=round_fast): return mpf_pos(a, prec, rnd), mpf_pos(b, prec, rnd) def mpc_neg((a, b), prec=None, rnd=round_fast): return mpf_neg(a, prec, rnd), mpf_neg(b, prec, rnd) def mpc_shift((a, b), n):
def mpf_exp(x, prec, rnd=round_fast): sign, man, exp, bc = x if not man: if not exp: return fone if x == fninf: return fzero return x mag = bc+exp # Fast handling e**n. TODO: the best cutoff depends on both the # size of n and the precision. if prec > 600 and exp >= 0: e = mpf_e(prec+10+int(1.45*mag)) return mpf_pow_int(e, (-1)**sign *(man<<exp), prec, rnd) if mag < -prec-10: return mpf_perturb(fone, sign, prec, rnd) # extra precision needs to be similar in magnitude to log_2(|x|) # for the modulo reduction, plus r for the error from squaring r times wp = prec + max(0, mag) if wp < 300: r = int(2*wp**0.4) if mag < 0: r = max(1, r + mag) wp += r + 20 t = to_fixed(x, wp) # abs(x) > 1? if mag > 1: lg2 = ln2_fixed(wp) n, t = divmod(t, lg2) else: n = 0 man = exp_series(t, wp, r) else: use_newton = False # put a bound on exp to avoid infinite recursion in exp_newton # TODO find a good bound if wp > LIM_EXP_SERIES2 and exp < 1000: if mag > 0: use_newton = True elif mag <= 0 and -mag <= ns_exp[-1]: i = bisect(ns_exp, -mag-1) if i < len(ns_exp): wp0 = precs_exp[i] if wp > wp0: use_newton = True if not use_newton: r = int(0.7 * wp**0.5) if mag < 0: r = max(1, r + mag) wp += r + 20 t = to_fixed(x, wp) if mag > 1: lg2 = ln2_fixed(wp) n, t = divmod(t, lg2) else: n = 0 man = exp_series2(t, wp, r) else: # if x is very small or very large use # exp(x + m) = exp(x) * e**m if mag > LIM_MAG: wp += mag*10 + 100 n = int(mag * math.log(2)) + 1 x = mpf_sub(x, from_int(n, wp), wp) elif mag <= 0: wp += -mag*10 + 100 if mag < 0: n = int(-mag * math.log(2)) + 1 x = mpf_add(x, from_int(n, wp), wp) res = exp_newton(x, wp) sign, man, exp, bc = res if mag < 0: t = mpf_pow_int(mpf_e(wp), n, wp) res = mpf_div(res, t, wp) sign, man, exp, bc = res if mag > LIM_MAG: t = mpf_pow_int(mpf_e(wp), n, wp) res = mpf_mul(res, t, wp) sign, man, exp, bc = res return normalize(sign, man, exp, bc, prec, rnd) bc = bitcount(man) return normalize(0, man, int(-wp+n), bc, prec, rnd)
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 mpi_delta(s, prec): sa, sb = s return mpf_sub(sb, sa, prec, round_up)