def mpc_besseljn(n, z, prec, rounding=round_fast): negate = n < 0 and n & 1 n = abs(n) origprec = prec prec += 20 + bitcount(abs(n)) zre, zim = z zre = to_fixed(zre, prec) zim = to_fixed(zim, prec) z2re = (zre**2 - zim**2) >> prec z2im = (zre * zim) >> (prec - 1) if not n: sre = tre = MP_ONE << prec sim = tim = MP_ZERO else: re, im = complex_int_pow(zre, zim, n) sre = tre = (re // int_fac(n)) >> ((n - 1) * prec + n) sim = tim = (im // int_fac(n)) >> ((n - 1) * prec + n) k = 1 while abs(tre) + abs(tim) > 3: p = -4 * k * (k + n) tre, tim = tre * z2re - tim * z2im, tim * z2re + tre * z2im tre = (tre // p) >> prec tim = (tim // p) >> prec sre += tre sim += tim k += 1 if negate: sre = -sre sim = -sim re = from_man_exp(sre, -prec, origprec, rounding) im = from_man_exp(sim, -prec, origprec, rounding) return (re, im)
def mpc_besseljn(n, z, prec, rounding=round_fast): negate = n < 0 and n & 1 n = abs(n) origprec = prec zre, zim = z mag = max(zre[2]+zre[3], zim[2]+zim[3]) prec += 20 + n*bitcount(n) + abs(mag) if mag < 0: prec -= n * mag zre = to_fixed(zre, prec) zim = to_fixed(zim, prec) z2re = (zre**2 - zim**2) >> prec z2im = (zre*zim) >> (prec-1) if not n: sre = tre = MPZ_ONE << prec sim = tim = MPZ_ZERO else: re, im = complex_int_pow(zre, zim, n) sre = tre = (re // ifac(n)) >> ((n-1)*prec + n) sim = tim = (im // ifac(n)) >> ((n-1)*prec + n) k = 1 while abs(tre) + abs(tim) > 3: p = -4*k*(k+n) tre, tim = tre*z2re - tim*z2im, tim*z2re + tre*z2im tre = (tre // p) >> prec tim = (tim // p) >> prec sre += tre sim += tim k += 1 if negate: sre = -sre sim = -sim re = from_man_exp(sre, -prec, origprec, rounding) im = from_man_exp(sim, -prec, origprec, rounding) return (re, im)
def mpc_zeta(s, prec, rnd): re, im = s wp = prec + 20 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) 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 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_ci_si_taylor(re, im, wp, which=0): # The following code is only designed for small arguments, # and not too small arguments (for relative accuracy) if re[1]: mag = re[2] + re[3] elif im[1]: mag = im[2] + im[3] if im[1]: mag = max(mag, im[2] + im[3]) if mag > 2 or mag < -wp: raise NotImplementedError wp += (2 - mag) zre = to_fixed(re, wp) zim = to_fixed(im, wp) z2re = (zim * zim - zre * zre) >> wp z2im = (-2 * zre * zim) >> wp tre = zre tim = zim one = MPZ_ONE << wp if which == 0: sre, sim, tre, tim, k = 0, 0, (MPZ_ONE << wp), 0, 2 else: sre, sim, tre, tim, k = zre, zim, zre, zim, 3 while max(abs(tre), abs(tim)) > 2: f = k * (k - 1) tre, tim = ((tre * z2re - tim * z2im) // f) >> wp, ( (tre * z2im + tim * z2re) // f) >> wp sre += tre // k sim += tim // k k += 2 return from_man_exp(sre, -wp), from_man_exp(sim, -wp)
def mpc_ci_si_taylor(re, im, wp, which=0): # The following code is only designed for small arguments, # and not too small arguments (for relative accuracy) if re[1]: mag = re[2]+re[3] elif im[1]: mag = im[2]+im[3] if im[1]: mag = max(mag, im[2]+im[3]) if mag > 2 or mag < -wp: raise NotImplementedError wp += (2-mag) zre = to_fixed(re, wp) zim = to_fixed(im, wp) z2re = (zim*zim-zre*zre)>>wp z2im = (-2*zre*zim)>>wp tre = zre tim = zim one = MPZ_ONE<<wp if which == 0: sre, sim, tre, tim, k = 0, 0, (MPZ_ONE<<wp), 0, 2 else: sre, sim, tre, tim, k = zre, zim, zre, zim, 3 while max(abs(tre), abs(tim)) > 2: f = k*(k-1) tre, tim = ((tre*z2re-tim*z2im)//f)>>wp, ((tre*z2im+tim*z2re)//f)>>wp sre += tre//k sim += tim//k k += 2 return from_man_exp(sre, -wp), from_man_exp(sim, -wp)
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 mpc_besseljn(n, z, prec): negate = n < 0 and n & 1 n = abs(n) origprec = prec prec += 20 + bitcount(abs(n)) zre, zim = z zre = to_fixed(zre, prec) zim = to_fixed(zim, prec) z2re = (zre**2 - zim**2) >> prec z2im = (zre*zim) >> (prec-1) if not n: sre = tre = MP_ONE << prec sim = tim = MP_ZERO else: re, im = complex_int_pow(zre, zim, n) sre = tre = (re // int_fac(n)) >> ((n-1)*prec + n) sim = tim = (im // int_fac(n)) >> ((n-1)*prec + n) k = 1 while abs(tre) + abs(tim) > 3: p = -4*k*(k+n) tre, tim = tre*z2re - tim*z2im, tim*z2re + tre*z2im tre = (tre // p) >> prec tim = (tim // p) >> prec sre += tre sim += tim k += 1 if negate: sre = -sre sim = -sim re = from_man_exp(sre, -prec, origprec, round_nearest) im = from_man_exp(sim, -prec, origprec, round_nearest) return (re, im)
def mpc_zeta(s, prec, rnd): re, im = s wp = prec + 20 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) 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 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_agm(a, b, prec, rnd=round_fast): """ Computes the arithmetic-geometric mean agm(a,b) for nonnegative mpf values a, b. """ asign, aman, aexp, abc = a bsign, bman, bexp, bbc = b if asign or bsign: raise ComplexResult("agm of a negative number") # Handle inf, nan or zero in either operand if not (aman and bman): if a == fnan or b == fnan: return fnan if a == finf: if b == fzero: return fnan return finf if b == finf: if a == fzero: return fnan return finf # agm(0,x) = agm(x,0) = 0 return fzero wp = prec + 20 amag = aexp+abc bmag = bexp+bbc mag_delta = amag - bmag # Reduce to roughly the same magnitude using floating-point AGM abs_mag_delta = abs(mag_delta) if abs_mag_delta > 10: while abs_mag_delta > 10: a, b = mpf_shift(mpf_add(a,b,wp),-1), \ mpf_sqrt(mpf_mul(a,b,wp),wp) abs_mag_delta //= 2 asign, aman, aexp, abc = a bsign, bman, bexp, bbc = b amag = aexp+abc bmag = bexp+bbc mag_delta = amag - bmag #print to_float(a), to_float(b) # Use agm(a,b) = agm(x*a,x*b)/x to obtain a, b ~= 1 min_mag = min(amag,bmag) max_mag = max(amag,bmag) n = 0 # If too small, we lose precision when going to fixed-point if min_mag < -8: n = -min_mag # If too large, we waste time using fixed-point with large numbers elif max_mag > 20: n = -max_mag if n: a = mpf_shift(a, n) b = mpf_shift(b, n) #print to_float(a), to_float(b) af = to_fixed(a, wp) bf = to_fixed(b, wp) g = agm_fixed(af, bf, wp) return from_man_exp(g, -wp-n, prec, rnd)
def mpf_agm(a, b, prec, rnd=round_fast): """ Computes the arithmetic-geometric mean agm(a,b) for nonnegative mpf values a, b. """ asign, aman, aexp, abc = a bsign, bman, bexp, bbc = b if asign or bsign: raise ComplexResult("agm of a negative number") # Handle inf, nan or zero in either operand if not (aman and bman): if a == fnan or b == fnan: return fnan if a == finf: if b == fzero: return fnan return finf if b == finf: if a == fzero: return fnan return finf # agm(0,x) = agm(x,0) = 0 return fzero wp = prec + 20 amag = aexp + abc bmag = bexp + bbc mag_delta = amag - bmag # Reduce to roughly the same magnitude using floating-point AGM abs_mag_delta = abs(mag_delta) if abs_mag_delta > 10: while abs_mag_delta > 10: a, b = mpf_shift(mpf_add(a,b,wp),-1), \ mpf_sqrt(mpf_mul(a,b,wp),wp) abs_mag_delta //= 2 asign, aman, aexp, abc = a bsign, bman, bexp, bbc = b amag = aexp + abc bmag = bexp + bbc mag_delta = amag - bmag #print to_float(a), to_float(b) # Use agm(a,b) = agm(x*a,x*b)/x to obtain a, b ~= 1 min_mag = min(amag, bmag) max_mag = max(amag, bmag) n = 0 # If too small, we lose precision when going to fixed-point if min_mag < -8: n = -min_mag # If too large, we waste time using fixed-point with large numbers elif max_mag > 20: n = -max_mag if n: a = mpf_shift(a, n) b = mpf_shift(b, n) #print to_float(a), to_float(b) af = to_fixed(a, wp) bf = to_fixed(b, wp) g = agm_fixed(af, bf, wp) return from_man_exp(g, -wp - n, 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 spouge_sum_complex(re, im, prec, a, c): re = to_fixed(re, prec) im = to_fixed(im, prec) sre, sim = c[0], 0 mag = ((re**2)>>prec) + ((im**2)>>prec) for k in xrange(1, a): M = mag + re*(2*k) + ((k**2) << prec) sre += (c[k] * (re + (k << prec))) // M sim -= (c[k] * im) // M re = from_man_exp(sre, -prec, prec, round_floor) im = from_man_exp(sim, -prec, prec, round_floor) return re, im
def spouge_sum_complex(re, im, prec, a, c): re = to_fixed(re, prec) im = to_fixed(im, prec) sre, sim = c[0], 0 mag = ((re**2) >> prec) + ((im**2) >> prec) for k in xrange(1, a): M = mag + re * (2 * k) + ((k**2) << prec) sre += (c[k] * (re + (k << prec))) // M sim -= (c[k] * im) // M re = from_man_exp(sre, -prec, prec, round_floor) im = from_man_exp(sim, -prec, prec, round_floor) return re, im
def glaisher_fixed(prec): wp = prec + 30 # Number of direct terms to sum before applying the Euler-Maclaurin # formula to the tail. TODO: choose more intelligently N = int(0.33 * prec + 5) ONE = MP_ONE << wp # Euler-Maclaurin, step 1: sum log(k)/k**2 for k from 2 to N-1 s = MP_ZERO for k in range(2, N): #print k, N s += log_int_fixed(k, wp) // k**2 logN = log_int_fixed(N, wp) #logN = to_fixed(mpf_log(from_int(N), wp+20), wp) # E-M step 2: integral of log(x)/x**2 from N to inf s += (ONE + logN) // N # E-M step 3: endpoint correction term f(N)/2 s += logN // (N**2 * 2) # E-M step 4: the series of derivatives pN = N**3 a = 1 b = -2 j = 3 fac = from_int(2) k = 1 while 1: # D(2*k-1) * B(2*k) / fac(2*k) [D(n) = nth derivative] D = ((a << wp) + b * logN) // pN D = from_man_exp(D, -wp) B = mpf_bernoulli(2 * k, wp) term = mpf_mul(B, D, wp) term = mpf_div(term, fac, wp) term = to_fixed(term, wp) if abs(term) < 100: break #if not k % 10: # print k, math.log(int(abs(term)), 10) s -= term # Advance derivative twice a, b, pN, j = b - a * j, -j * b, pN * N, j + 1 a, b, pN, j = b - a * j, -j * b, pN * N, j + 1 k += 1 fac = mpf_mul_int(fac, (2 * k) * (2 * k - 1), wp) # A = exp((6*s/pi**2 + log(2*pi) + euler)/12) pi = pi_fixed(wp) s *= 6 s = (s << wp) // (pi**2 >> wp) s += euler_fixed(wp) s += to_fixed(mpf_log(from_man_exp(2 * pi, -wp), wp), wp) s //= 12 A = mpf_exp(from_man_exp(s, -wp), wp) return to_fixed(A, prec)
def glaisher_fixed(prec): wp = prec + 30 # Number of direct terms to sum before applying the Euler-Maclaurin # formula to the tail. TODO: choose more intelligently N = int(0.33*prec + 5) ONE = MPZ_ONE << wp # Euler-Maclaurin, step 1: sum log(k)/k**2 for k from 2 to N-1 s = MPZ_ZERO for k in range(2, N): #print k, N s += log_int_fixed(k, wp) // k**2 logN = log_int_fixed(N, wp) #logN = to_fixed(mpf_log(from_int(N), wp+20), wp) # E-M step 2: integral of log(x)/x**2 from N to inf s += (ONE + logN) // N # E-M step 3: endpoint correction term f(N)/2 s += logN // (N**2 * 2) # E-M step 4: the series of derivatives pN = N**3 a = 1 b = -2 j = 3 fac = from_int(2) k = 1 while 1: # D(2*k-1) * B(2*k) / fac(2*k) [D(n) = nth derivative] D = ((a << wp) + b*logN) // pN D = from_man_exp(D, -wp) B = mpf_bernoulli(2*k, wp) term = mpf_mul(B, D, wp) term = mpf_div(term, fac, wp) term = to_fixed(term, wp) if abs(term) < 100: break #if not k % 10: # print k, math.log(int(abs(term)), 10) s -= term # Advance derivative twice a, b, pN, j = b-a*j, -j*b, pN*N, j+1 a, b, pN, j = b-a*j, -j*b, pN*N, j+1 k += 1 fac = mpf_mul_int(fac, (2*k)*(2*k-1), wp) # A = exp((6*s/pi**2 + log(2*pi) + euler)/12) pi = pi_fixed(wp) s *= 6 s = (s << wp) // (pi**2 >> wp) s += euler_fixed(wp) s += to_fixed(mpf_log(from_man_exp(2*pi, -wp), wp), wp) s //= 12 A = mpf_exp(from_man_exp(s, -wp), wp) return to_fixed(A, prec)
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_atan(x, prec, rnd=round_fast): sign, man, exp, bc = x if not man: if x == fzero: return fzero if x == finf: return atan_inf(0, prec, rnd) if x == fninf: return atan_inf(1, prec, rnd) return fnan mag = exp + bc # Essentially infinity if mag > prec+20: return atan_inf(sign, prec, rnd) # Essentially ~ x if -mag > prec+20: return mpf_perturb(x, 1-sign, prec, rnd) wp = prec + 30 + abs(mag) # For large x, use atan(x) = pi/2 - atan(1/x) if mag >= 2: x = mpf_rdiv_int(1, x, wp) reciprocal = True else: reciprocal = False t = to_fixed(x, wp) if sign: t = -t if wp < ATAN_TAYLOR_PREC: a = atan_taylor(t, wp) else: a = atan_newton(t, wp) if reciprocal: a = ((pi_fixed(wp)>>1)+1) - a if sign: a = -a return from_man_exp(a, -wp, prec, rnd)
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 # Fast handling e**n. TODO: the best cutoff depends on both the # size of n and the precision. if prec > 600 and exp >= 0: return mpf_pow_int(mpf_e(prec + 10), (-1)**sign * (man << exp), prec, rnd) mag = bc + exp 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: 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) bc = wp - 2 + bctable[int(man >> (wp - 2))] return normalize(0, man, int(-wp + n), bc, prec, rnd)
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 # Fast handling e**n. TODO: the best cutoff depends on both the # size of n and the precision. if prec > 600 and exp >= 0: return mpf_pow_int(mpf_e(prec+10), (-1)**sign *(man<<exp), prec, rnd) mag = bc+exp 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: 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) bc = wp - 2 + bctable[int(man >> (wp - 2))] return normalize(0, man, int(-wp+n), bc, prec, rnd)
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 mpc_ci_si_taylor(re, im, wp, which=0): zre = to_fixed(re, wp) zim = to_fixed(im, wp) z2re = (zim*zim-zre*zre)>>wp z2im = (-2*zre*zim)>>wp tre = zre tim = zim one = MP_ONE<<wp if which == 0: sre, sim, tre, tim, k = 0, 0, (MP_ONE<<wp), 0, 2 else: sre, sim, tre, tim, k = zre, zim, zre, zim, 3 while max(abs(tre), abs(tim)) > 2: f = k*(k-1) tre, tim = ((tre*z2re-tim*z2im)//f)>>wp, ((tre*z2im+tim*z2re)//f)>>wp sre += tre//k sim += tim//k k += 2 return from_man_exp(sre, -wp), from_man_exp(sim, -wp)
def mpc_ci_si_taylor(re, im, wp, which=0): zre = to_fixed(re, wp) zim = to_fixed(im, wp) z2re = (zim * zim - zre * zre) >> wp z2im = (-2 * zre * zim) >> wp tre = zre tim = zim one = MP_ONE << wp if which == 0: sre, sim, tre, tim, k = 0, 0, (MP_ONE << wp), 0, 2 else: sre, sim, tre, tim, k = zre, zim, zre, zim, 3 while max(abs(tre), abs(tim)) > 2: f = k * (k - 1) tre, tim = ((tre * z2re - tim * z2im) // f) >> wp, ( (tre * z2im + tim * z2re) // f) >> wp sre += tre // k sim += tim // k k += 2 return from_man_exp(sre, -wp), from_man_exp(sim, -wp)
def log_int_fixed(n, prec): if n in log_int_cache: value, vprec = log_int_cache[n] if vprec >= prec: return value >> (vprec - prec) extra = 30 vprec = prec + extra v = to_fixed(mpf_log(from_int(n), vprec+5), vprec) if n < MAX_LOG_INT_CACHE: log_int_cache[n] = (v, vprec) return v >> extra
def mpf_ei(x, prec, rnd=round_fast, e1=False): if e1: x = mpf_neg(x) sign, man, exp, bc = x if e1 and not sign: if x == fzero: return finf raise ComplexResult("E1(x) for x < 0") if man: xabs = 0, man, exp, bc xmag = exp + bc wp = prec + 20 can_use_asymp = xmag > wp if not can_use_asymp: if exp >= 0: xabsint = man << exp else: xabsint = man >> (-exp) can_use_asymp = xabsint > int(wp * 0.693) + 10 if can_use_asymp: if xmag > wp: v = fone else: v = from_man_exp(ei_asymptotic(to_fixed(x, wp), wp), -wp) v = mpf_mul(v, mpf_exp(x, wp), wp) v = mpf_div(v, x, prec, rnd) else: wp += 2 * int(to_int(xabs)) u = to_fixed(x, wp) v = ei_taylor(u, wp) + euler_fixed(wp) t1 = from_man_exp(v, -wp) t2 = mpf_log(xabs, wp) v = mpf_add(t1, t2, prec, rnd) else: if x == fzero: v = fninf elif x == finf: v = finf elif x == fninf: v = fzero else: v = fnan if e1: v = mpf_neg(v) return v
def mpf_ei(x, prec, rnd=round_fast, e1=False): if e1: x = mpf_neg(x) sign, man, exp, bc = x if e1 and not sign: if x == fzero: return finf raise ComplexResult("E1(x) for x < 0") if man: xabs = 0, man, exp, bc xmag = exp+bc wp = prec + 20 can_use_asymp = xmag > wp if not can_use_asymp: if exp >= 0: xabsint = man << exp else: xabsint = man >> (-exp) can_use_asymp = xabsint > int(wp*0.693) + 10 if can_use_asymp: if xmag > wp: v = fone else: v = from_man_exp(ei_asymptotic(to_fixed(x, wp), wp), -wp) v = mpf_mul(v, mpf_exp(x, wp), wp) v = mpf_div(v, x, prec, rnd) else: wp += 2*int(to_int(xabs)) u = to_fixed(x, wp) v = ei_taylor(u, wp) + euler_fixed(wp) t1 = from_man_exp(v,-wp) t2 = mpf_log(xabs,wp) v = mpf_add(t1, t2, prec, rnd) else: if x == fzero: v = fninf elif x == finf: v = finf elif x == fninf: v = fzero else: v = fnan if e1: v = mpf_neg(v) return v
def mpc_nthroot(z, n, prec, rnd=round_fast): """ Complex n-th root. Use Newton method as in the real case when it is faster, otherwise use z**(1/n) """ a, b = z if a[0] == 0 and b == fzero: re = mpf_nthroot(a, n, prec, rnd) return (re, fzero) if n < 2: if n == 0: return mpc_one if n == 1: return mpc_pos((a, b), prec, rnd) if n == -1: return mpc_div(mpc_one, (a, b), prec, rnd) inverse = mpc_nthroot((a, b), -n, prec+5, reciprocal_rnd[rnd]) return mpc_div(mpc_one, inverse, prec, rnd) if n <= 20: prec2 = int(1.2 * (prec + 10)) asign, aman, aexp, abc = a bsign, bman, bexp, bbc = b pf = mpc_abs((a,b), prec) if pf[-2] + pf[-1] > -10 and pf[-2] + pf[-1] < prec: af = to_fixed(a, prec2) bf = to_fixed(b, prec2) re, im = mpc_nthroot_fixed(af, bf, n, prec2) extra = 10 re = from_man_exp(re, -prec2-extra, prec2, rnd) im = from_man_exp(im, -prec2-extra, prec2, rnd) return re, im fn = from_int(n) prec2 = prec+10 + 10 nth = mpf_rdiv_int(1, fn, prec2) re, im = mpc_pow((a, b), (nth, fzero), prec2, rnd) 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_nthroot(z, n, prec, rnd=round_fast): """ Complex n-th root. Use Newton method as in the real case when it is faster, otherwise use z**(1/n) """ a, b = z if a[0] == 0 and b == fzero: re = mpf_nthroot(a, n, prec, rnd) return (re, fzero) if n < 2: if n == 0: return mpc_one if n == 1: return mpc_pos((a, b), prec, rnd) if n == -1: return mpc_div(mpc_one, (a, b), prec, rnd) inverse = mpc_nthroot((a, b), -n, prec + 5, reciprocal_rnd[rnd]) return mpc_div(mpc_one, inverse, prec, rnd) if n <= 20: prec2 = int(1.2 * (prec + 10)) asign, aman, aexp, abc = a bsign, bman, bexp, bbc = b pf = mpc_abs((a, b), prec) if pf[-2] + pf[-1] > -10 and pf[-2] + pf[-1] < prec: af = to_fixed(a, prec2) bf = to_fixed(b, prec2) re, im = mpc_nthroot_fixed(af, bf, n, prec2) extra = 10 re = from_man_exp(re, -prec2 - extra, prec2, rnd) im = from_man_exp(im, -prec2 - extra, prec2, rnd) return re, im fn = from_int(n) prec2 = prec + 10 + 10 nth = mpf_rdiv_int(1, fn, prec2) re, im = mpc_pow((a, b), (nth, fzero), prec2, rnd) 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 mertens_fixed(prec): wp = prec + 20 m = 2 s = mpf_euler(wp) while 1: t = mpf_zeta_int(m, wp) if t == fone: break t = mpf_log(t, wp) t = mpf_mul_int(t, moebius(m), wp) t = mpf_div(t, from_int(m), wp) s = mpf_add(s, t) m += 1 return to_fixed(s, prec)
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 mpf_ci_si_taylor(x, wp, which=0): """ 0 - Ci(x) - (euler+log(x)) 1 - Si(x) """ x = to_fixed(x, wp) x2 = -(x * x) >> wp if which == 0: s, t, k = 0, (MP_ONE << wp), 2 else: s, t, k = x, x, 3 while t: t = (t * x2 // (k * (k - 1))) >> wp s += t // k k += 2 return from_man_exp(s, -wp)
def mpf_ci_si_taylor(x, wp, which=0): """ 0 - Ci(x) - (euler+log(x)) 1 - Si(x) """ x = to_fixed(x, wp) x2 = -(x*x) >> wp if which == 0: s, t, k = 0, (MPZ_ONE<<wp), 2 else: s, t, k = x, x, 3 while t: t = (t*x2//(k*(k-1)))>>wp s += t//k k += 2 return from_man_exp(s, -wp)
def mpf_besseljn(n, x, prec, rounding=round_fast): negate = n < 0 and n & 1 n = abs(n) origprec = prec prec += 20 + bitcount(abs(n)) x = to_fixed(x, prec) x2 = (x**2) >> prec if not n: s = t = MP_ONE << prec else: s = t = (x**n // int_fac(n)) >> ((n - 1) * prec + n) k = 1 while t: t = ((t * x2) // (-4 * k * (k + n))) >> prec s += t k += 1 if negate: s = -s return from_man_exp(s, -prec, origprec, rounding)
def mpf_besseljn(n, x, prec): negate = n < 0 and n & 1 n = abs(n) origprec = prec prec += 20 + bitcount(abs(n)) x = to_fixed(x, prec) x2 = (x**2) >> prec if not n: s = t = MP_ONE << prec else: s = t = (x**n // int_fac(n)) >> ((n-1)*prec + n) k = 1 while t: t = ((t * x2) // (-4*k*(k+n))) >> prec s += t k += 1 if negate: s = -s return from_man_exp(s, -prec, origprec, round_nearest)
def log_int_fixed(n, prec, ln2=None): """ Fast computation of log(n), caching the value for small n, intended for zeta sums. """ if n in log_int_cache: value, vprec = log_int_cache[n] if vprec >= prec: return value >> (vprec - prec) wp = prec + 10 if wp <= LOG_TAYLOR_SHIFT: if ln2 is None: ln2 = ln2_fixed(wp) r = bitcount(n) x = n << (wp - r) v = log_taylor_cached(x, wp) + r * ln2 else: v = to_fixed(mpf_log(from_int(n), wp + 5), wp) if n < MAX_LOG_INT_CACHE: log_int_cache[n] = (v, wp) return v >> (wp - prec)
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_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_besseljn(n, x, prec, rounding=round_fast): prec += 50 negate = n < 0 and n & 1 mag = x[2]+x[3] n = abs(n) wp = prec + 20 + n*bitcount(n) if mag < 0: wp -= n * mag x = to_fixed(x, wp) x2 = (x**2) >> wp if not n: s = t = MPZ_ONE << wp else: s = t = (x**n // ifac(n)) >> ((n-1)*wp + n) k = 1 while t: t = ((t * x2) // (-4*k*(k+n))) >> wp s += t k += 1 if negate: s = -s return from_man_exp(s, -wp, prec, rounding)
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 mpf_besseljn(n, x, prec, rounding=round_fast): prec += 50 negate = n < 0 and n & 1 mag = x[2] + x[3] n = abs(n) wp = prec + 20 + n * bitcount(n) if mag < 0: wp -= n * mag x = to_fixed(x, wp) x2 = (x**2) >> wp if not n: s = t = MP_ONE << wp else: s = t = (x**n // int_fac(n)) >> ((n - 1) * wp + n) k = 1 while t: t = ((t * x2) // (-4 * k * (k + n))) >> wp s += t k += 1 if negate: s = -s return from_man_exp(s, -wp, prec, rounding)
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 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 sqrt_fixed(x, prec): return to_fixed(mpf_sqrt(from_man_exp(x, -prec, prec), prec), prec)
def spouge_sum_real(x, prec, a, c): x = to_fixed(x, prec) s = c[0] for k in xrange(1, a): s += (c[k] << prec) // (x + (k << prec)) return from_man_exp(s, -prec, prec, round_floor)
def _djacobi_theta2(z, q, nd): MIN = 2 extra1 = 10 extra2 = 20 if isinstance(q, mpf) and isinstance(z, mpf): wp = mp.prec + extra1 x = to_fixed(q._mpf_, wp) x2 = (x*x) >> wp a = b = x2 c1, s1 = cos_sin(z._mpf_, wp) cn = c1 = to_fixed(c1, wp) sn = s1 = to_fixed(s1, wp) c2 = (c1*c1 - s1*s1) >> wp s2 = (c1 * s1) >> (wp - 1) cn, sn = (cn*c2 - sn*s2) >> wp, (sn*c2 + cn*s2) >> wp if (nd&1): s = s1 + ((a * sn * 3**nd) >> wp) else: s = c1 + ((a * cn * 3**nd) >> wp) n = 2 while abs(a) > MIN: b = (b*x2) >> wp a = (a*b) >> wp cn, sn = (cn*c2 - sn*s2) >> wp, (sn*c2 + cn*s2) >> wp if nd&1: s += (a * sn * (2*n+1)**nd) >> wp else: s += (a * cn * (2*n+1)**nd) >> wp n += 1 s = -(s << 1) s = mpf(from_man_exp(s, -wp, mp.prec, 'n')) # case z real, q complex elif isinstance(z, mpf): wp = mp.prec + extra2 xre, xim = q._mpc_ xre = to_fixed(xre, wp) xim = to_fixed(xim, wp) x2re = (xre*xre - xim*xim) >> wp x2im = (xre*xim) >> (wp - 1) are = bre = x2re aim = bim = x2im c1, s1 = cos_sin(z._mpf_, wp) cn = c1 = to_fixed(c1, wp) sn = s1 = to_fixed(s1, wp) c2 = (c1*c1 - s1*s1) >> wp s2 = (c1 * s1) >> (wp - 1) cn, sn = (cn*c2 - sn*s2) >> wp, (sn*c2 + cn*s2) >> wp if (nd&1): sre = s1 + ((are * sn * 3**nd) >> wp) sim = ((aim * sn * 3**nd) >> wp) else: sre = c1 + ((are * cn * 3**nd) >> wp) sim = ((aim * cn * 3**nd) >> wp) n = 5 while are**2 + aim**2 > MIN: bre, bim = (bre * x2re - bim * x2im) >> wp, \ (bre * x2im + bim * x2re) >> wp are, aim = (are * bre - aim * bim) >> wp, \ (are * bim + aim * bre) >> wp cn, sn = (cn*c2 - sn*s2) >> wp, (sn*c2 + cn*s2) >> wp if (nd&1): sre += ((are * sn * n**nd) >> wp) sim += ((aim * sn * n**nd) >> wp) else: sre += ((are * cn * n**nd) >> wp) sim += ((aim * cn * n**nd) >> wp) n += 2 sre = -(sre << 1) sim = -(sim << 1) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) #case z complex, q real elif isinstance(q, mpf): wp = mp.prec + extra2 x = to_fixed(q._mpf_, wp) x2 = (x*x) >> wp a = b = x2 prec0 = mp.prec mp.prec = wp c1 = cos(z) s1 = sin(z) mp.prec = prec0 cnre = c1re = to_fixed(c1.real._mpf_, wp) cnim = c1im = to_fixed(c1.imag._mpf_, wp) snre = s1re = to_fixed(s1.real._mpf_, wp) snim = s1im = to_fixed(s1.imag._mpf_, wp) #c2 = (c1*c1 - s1*s1) >> wp c2re = (c1re*c1re - c1im*c1im - s1re*s1re + s1im*s1im) >> wp c2im = (c1re*c1im - s1re*s1im) >> (wp - 1) #s2 = (c1 * s1) >> (wp - 1) s2re = (c1re*s1re - c1im*s1im) >> (wp - 1) s2im = (c1re*s1im + c1im*s1re) >> (wp - 1) #cn, sn = (cn*c2 - sn*s2) >> wp, (sn*c2 + cn*s2) >> wp t1 = (cnre*c2re - cnim*c2im - snre*s2re + snim*s2im) >> wp t2 = (cnre*c2im + cnim*c2re - snre*s2im - snim*s2re) >> wp t3 = (snre*c2re - snim*c2im + cnre*s2re - cnim*s2im) >> wp t4 = (snre*c2im + snim*c2re + cnre*s2im + cnim*s2re) >> wp cnre = t1 cnim = t2 snre = t3 snim = t4 if (nd&1): sre = s1re + ((a * snre * 3**nd) >> wp) sim = s1im + ((a * snim * 3**nd) >> wp) else: sre = c1re + ((a * cnre * 3**nd) >> wp) sim = c1im + ((a * cnim * 3**nd) >> wp) n = 5 while abs(a) > MIN: b = (b*x2) >> wp a = (a*b) >> wp t1 = (cnre*c2re - cnim*c2im - snre*s2re + snim*s2im) >> wp t2 = (cnre*c2im + cnim*c2re - snre*s2im - snim*s2re) >> wp t3 = (snre*c2re - snim*c2im + cnre*s2re - cnim*s2im) >> wp t4 = (snre*c2im + snim*c2re + cnre*s2im + cnim*s2re) >> wp cnre = t1 cnim = t2 snre = t3 snim = t4 if (nd&1): sre += ((a * snre * n**nd) >> wp) sim += ((a * snim * n**nd) >> wp) else: sre += ((a * cnre * n**nd) >> wp) sim += ((a * cnim * n**nd) >> wp) n += 2 sre = -(sre << 1) sim = -(sim << 1) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) # case z and q complex else: wp = mp.prec + extra2 xre, xim = q._mpc_ xre = to_fixed(xre, wp) xim = to_fixed(xim, wp) x2re = (xre*xre - xim*xim) >> wp x2im = (xre*xim) >> (wp - 1) are = bre = x2re aim = bim = x2im prec0 = mp.prec mp.prec = wp # cos(2*z), siz(2*z) with z complex c1 = cos(z) s1 = sin(z) mp.prec = prec0 cnre = c1re = to_fixed(c1.real._mpf_, wp) cnim = c1im = to_fixed(c1.imag._mpf_, wp) snre = s1re = to_fixed(s1.real._mpf_, wp) snim = s1im = to_fixed(s1.imag._mpf_, wp) c2re = (c1re*c1re - c1im*c1im - s1re*s1re + s1im*s1im) >> wp c2im = (c1re*c1im - s1re*s1im) >> (wp - 1) s2re = (c1re*s1re - c1im*s1im) >> (wp - 1) s2im = (c1re*s1im + c1im*s1re) >> (wp - 1) t1 = (cnre*c2re - cnim*c2im - snre*s2re + snim*s2im) >> wp t2 = (cnre*c2im + cnim*c2re - snre*s2im - snim*s2re) >> wp t3 = (snre*c2re - snim*c2im + cnre*s2re - cnim*s2im) >> wp t4 = (snre*c2im + snim*c2re + cnre*s2im + cnim*s2re) >> wp cnre = t1 cnim = t2 snre = t3 snim = t4 if (nd&1): sre = s1re + (((are * snre - aim * snim) * 3**nd) >> wp) sim = s1im + (((are * snim + aim * snre)* 3**nd) >> wp) else: sre = c1re + (((are * cnre - aim * cnim) * 3**nd) >> wp) sim = c1im + (((are * cnim + aim * cnre)* 3**nd) >> wp) n = 5 while are**2 + aim**2 > MIN: bre, bim = (bre * x2re - bim * x2im) >> wp, \ (bre * x2im + bim * x2re) >> wp are, aim = (are * bre - aim * bim) >> wp, \ (are * bim + aim * bre) >> wp #cn, sn = (cn*c1 - sn*s1) >> wp, (sn*c1 + cn*s1) >> wp t1 = (cnre*c2re - cnim*c2im - snre*s2re + snim*s2im) >> wp t2 = (cnre*c2im + cnim*c2re - snre*s2im - snim*s2re) >> wp t3 = (snre*c2re - snim*c2im + cnre*s2re - cnim*s2im) >> wp t4 = (snre*c2im + snim*c2re + cnre*s2im + cnim*s2re) >> wp cnre = t1 cnim = t2 snre = t3 snim = t4 if (nd&1): sre += (((are * snre - aim * snim) * n**nd) >> wp) sim += (((aim * snre + are * snim) * n**nd) >> wp) else: sre += (((are * cnre - aim * cnim) * n**nd) >> wp) sim += (((aim * cnre + are * cnim) * n**nd) >> wp) n += 2 sre = -(sre << 1) sim = -(sim << 1) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) s *= nthroot(q, 4) if (nd&1): return (-1)**(nd//2) * s else: return (-1)**(1 + nd//2) * s
def _jacobi_theta3(z, q): extra1 = 10 extra2 = 20 MIN = 2 if z == zero: if isinstance(q, mpf): wp = mp.prec + extra1 x = to_fixed(q._mpf_, wp) s = x a = b = x x2 = (x*x) >> wp while abs(a) > MIN: b = (b*x2) >> wp a = (a*b) >> wp s += a s = (1 << wp) + (s << 1) s = mpf(from_man_exp(s, -wp, mp.prec, 'n')) return s else: wp = mp.prec + extra1 xre, xim = q._mpc_ xre = to_fixed(xre, wp) xim = to_fixed(xim, wp) x2re = (xre*xre - xim*xim) >> wp x2im = (xre*xim) >> (wp - 1) sre = are = bre = xre sim = aim = bim = xim while are**2 + aim**2 > MIN: bre, bim = (bre * x2re - bim * x2im) >> wp, \ (bre * x2im + bim * x2re) >> wp are, aim = (are * bre - aim * bim) >> wp, \ (are * bim + aim * bre) >> wp sre += are sim += aim sre = (1 << wp) + (sre << 1) sim = (sim << 1) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) return s else: if isinstance(q, mpf) and isinstance(z, mpf): s = MP_ZERO wp = mp.prec + extra1 x = to_fixed(q._mpf_, wp) a = b = x x2 = (x*x) >> wp c1, s1 = cos_sin(mpf_shift(z._mpf_, 1), wp) c1 = to_fixed(c1, wp) s1 = to_fixed(s1, wp) cn = c1 sn = s1 s += (a * cn) >> wp while abs(a) > MIN: b = (b*x2) >> wp a = (a*b) >> wp cn, sn = (cn*c1 - sn*s1) >> wp, (sn*c1 + cn*s1) >> wp s += (a * cn) >> wp s = (1 << wp) + (s << 1) s = mpf(from_man_exp(s, -wp, mp.prec, 'n')) return s # case z real, q complex elif isinstance(z, mpf): wp = mp.prec + extra2 xre, xim = q._mpc_ xre = to_fixed(xre, wp) xim = to_fixed(xim, wp) x2re = (xre*xre - xim*xim) >> wp x2im = (xre*xim) >> (wp - 1) are = bre = xre aim = bim = xim c1, s1 = cos_sin(mpf_shift(z._mpf_, 1), wp) c1 = to_fixed(c1, wp) s1 = to_fixed(s1, wp) cn = c1 sn = s1 sre = (are * cn) >> wp sim = (aim * cn) >> wp while are**2 + aim**2 > MIN: bre, bim = (bre * x2re - bim * x2im) >> wp, \ (bre * x2im + bim * x2re) >> wp are, aim = (are * bre - aim * bim) >> wp, \ (are * bim + aim * bre) >> wp cn, sn = (cn*c1 - sn*s1) >> wp, (sn*c1 + cn*s1) >> wp sre += (are * cn) >> wp sim += (aim * cn) >> wp sre = (1 << wp) + (sre << 1) sim = (sim << 1) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) return s #case z complex, q real elif isinstance(q, mpf): wp = mp.prec + extra2 x = to_fixed(q._mpf_, wp) a = b = x x2 = (x*x) >> wp prec0 = mp.prec mp.prec = wp c1 = cos(2*z) s1 = sin(2*z) mp.prec = prec0 cnre = c1re = to_fixed(c1.real._mpf_, wp) cnim = c1im = to_fixed(c1.imag._mpf_, wp) snre = s1re = to_fixed(s1.real._mpf_, wp) snim = s1im = to_fixed(s1.imag._mpf_, wp) sre = (a * cnre) >> wp sim = (a * cnim) >> wp while abs(a) > MIN: b = (b*x2) >> wp a = (a*b) >> wp t1 = (cnre*c1re - cnim*c1im - snre*s1re + snim*s1im) >> wp t2 = (cnre*c1im + cnim*c1re - snre*s1im - snim*s1re) >> wp t3 = (snre*c1re - snim*c1im + cnre*s1re - cnim*s1im) >> wp t4 = (snre*c1im + snim*c1re + cnre*s1im + cnim*s1re) >> wp cnre = t1 cnim = t2 snre = t3 snim = t4 sre += (a * cnre) >> wp sim += (a * cnim) >> wp sre = (1 << wp) + (sre << 1) sim = (sim << 1) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) return s # case z and q complex else: wp = mp.prec + extra2 xre, xim = q._mpc_ xre = to_fixed(xre, wp) xim = to_fixed(xim, wp) x2re = (xre*xre - xim*xim) >> wp x2im = (xre*xim) >> (wp - 1) are = bre = xre aim = bim = xim prec0 = mp.prec mp.prec = wp # cos(2*z), sin(2*z) with z complex c1 = cos(2*z) s1 = sin(2*z) mp.prec = prec0 cnre = c1re = to_fixed(c1.real._mpf_, wp) cnim = c1im = to_fixed(c1.imag._mpf_, wp) snre = s1re = to_fixed(s1.real._mpf_, wp) snim = s1im = to_fixed(s1.imag._mpf_, wp) sre = (are * cnre - aim * cnim) >> wp sim = (aim * cnre + are * cnim) >> wp while are**2 + aim**2 > MIN: bre, bim = (bre * x2re - bim * x2im) >> wp, \ (bre * x2im + bim * x2re) >> wp are, aim = (are * bre - aim * bim) >> wp, \ (are * bim + aim * bre) >> wp t1 = (cnre*c1re - cnim*c1im - snre*s1re + snim*s1im) >> wp t2 = (cnre*c1im + cnim*c1re - snre*s1im - snim*s1re) >> wp t3 = (snre*c1re - snim*c1im + cnre*s1re - cnim*s1im) >> wp t4 = (snre*c1im + snim*c1re + cnre*s1im + cnim*s1re) >> wp cnre = t1 cnim = t2 snre = t3 snim = t4 sre += (are * cnre - aim * cnim) >> wp sim += (aim * cnre + are * cnim) >> wp sre = (1 << wp) + (sre << 1) sim = (sim << 1) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) return s
def mpc_zetasum(s, a, n, derivatives, reflect, prec): """ Fast version of mp._zetasum, assuming s = complex, a = integer. """ wp = prec + 10 have_derivatives = derivatives != [0] have_one_derivative = len(derivatives) == 1 # parse s sre, sim = s critical_line = (sre == fhalf) sre = to_fixed(sre, wp) sim = to_fixed(sim, wp) maxd = max(derivatives) if not have_one_derivative: derivatives = range(maxd+1) # x_d = 0, y_d = 0 xre = [MPZ_ZERO for d in derivatives] xim = [MPZ_ZERO for d in derivatives] if reflect: yre = [MPZ_ZERO for d in derivatives] yim = [MPZ_ZERO for d in derivatives] else: yre = yim = [] one = MPZ_ONE << wp one_2wp = MPZ_ONE << (2*wp) for w in xrange(a, a+n+1): log = log_int_fixed(w, wp) cos, sin = cos_sin_fixed_prod(-sim*log, wp) if critical_line: u = one_2wp // sqrt_fixed(w << wp, wp) else: u = exp_fixed_prod(-sre*log, wp) xterm_re = (u * cos) >> wp xterm_im = (u * sin) >> wp if reflect: reciprocal = (one_2wp // (u*w)) yterm_re = (reciprocal * cos) >> wp yterm_im = (reciprocal * sin) >> wp if have_derivatives: if have_one_derivative: log = pow_fixed(log, maxd, wp) xre[0] += (xterm_re * log) >> wp xim[0] += (xterm_im * log) >> wp if reflect: yre[0] += (yterm_re * log) >> wp yim[0] += (yterm_im * log) >> wp else: t = MPZ_ONE << wp for d in derivatives: xre[d] += (xterm_re * t) >> wp xim[d] += (xterm_im * t) >> wp if reflect: yre[d] += (yterm_re * t) >> wp yim[d] += (yterm_im * t) >> wp t = (t * log) >> wp else: xre[0] += xterm_re xim[0] += xterm_im if reflect: yre[0] += yterm_re yim[0] += yterm_im if have_derivatives: if have_one_derivative: if maxd % 2: xre[0] = -xre[0] xim[0] = -xim[0] if reflect: yre[0] = -yre[0] yim[0] = -yim[0] else: xre = [(-1)**d * xre[d] for d in derivatives] xim = [(-1)**d * xim[d] for d in derivatives] if reflect: yre = [(-1)**d * yre[d] for d in derivatives] yim = [(-1)**d * yim[d] for d in derivatives] xs = [(from_man_exp(xa, -wp, prec, 'n'), from_man_exp(xb, -wp, prec, 'n')) for (xa, xb) in zip(xre, xim)] ys = [(from_man_exp(ya, -wp, prec, 'n'), from_man_exp(yb, -wp, prec, 'n')) for (ya, yb) in zip(yre, yim)] return xs, ys
def _djacobi_theta3(z, q, nd): """nd=1,2,3 order of the derivative with respect to z""" MIN = 2 extra1 = 10 extra2 = 20 if isinstance(q, mpf) and isinstance(z, mpf): s = MP_ZERO wp = mp.prec + extra1 x = to_fixed(q._mpf_, wp) a = b = x x2 = (x*x) >> wp c1, s1 = cos_sin(mpf_shift(z._mpf_, 1), wp) c1 = to_fixed(c1, wp) s1 = to_fixed(s1, wp) cn = c1 sn = s1 if (nd&1): s += (a * sn) >> wp else: s += (a * cn) >> wp n = 2 while abs(a) > MIN: b = (b*x2) >> wp a = (a*b) >> wp cn, sn = (cn*c1 - sn*s1) >> wp, (sn*c1 + cn*s1) >> wp if nd&1: s += (a * sn * n**nd) >> wp else: s += (a * cn * n**nd) >> wp n += 1 s = -(s << (nd+1)) s = mpf(from_man_exp(s, -wp, mp.prec, 'n')) # case z real, q complex elif isinstance(z, mpf): wp = mp.prec + extra2 xre, xim = q._mpc_ xre = to_fixed(xre, wp) xim = to_fixed(xim, wp) x2re = (xre*xre - xim*xim) >> wp x2im = (xre*xim) >> (wp - 1) are = bre = xre aim = bim = xim c1, s1 = cos_sin(mpf_shift(z._mpf_, 1), wp) c1 = to_fixed(c1, wp) s1 = to_fixed(s1, wp) cn = c1 sn = s1 if (nd&1): sre = (are * sn) >> wp sim = (aim * sn) >> wp else: sre = (are * cn) >> wp sim = (aim * cn) >> wp n = 2 while are**2 + aim**2 > MIN: bre, bim = (bre * x2re - bim * x2im) >> wp, \ (bre * x2im + bim * x2re) >> wp are, aim = (are * bre - aim * bim) >> wp, \ (are * bim + aim * bre) >> wp cn, sn = (cn*c1 - sn*s1) >> wp, (sn*c1 + cn*s1) >> wp if nd&1: sre += (are * sn * n**nd) >> wp sim += (aim * sn * n**nd) >> wp else: sre += (are * cn * n**nd) >> wp sim += (aim * cn * n**nd) >> wp n += 1 sre = -(sre << (nd+1)) sim = -(sim << (nd+1)) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) #case z complex, q real elif isinstance(q, mpf): wp = mp.prec + extra2 x = to_fixed(q._mpf_, wp) a = b = x x2 = (x*x) >> wp prec0 = mp.prec mp.prec = wp c1 = cos(2*z) s1 = sin(2*z) mp.prec = prec0 cnre = c1re = to_fixed(c1.real._mpf_, wp) cnim = c1im = to_fixed(c1.imag._mpf_, wp) snre = s1re = to_fixed(s1.real._mpf_, wp) snim = s1im = to_fixed(s1.imag._mpf_, wp) if (nd&1): sre = (a * snre) >> wp sim = (a * snim) >> wp else: sre = (a * cnre) >> wp sim = (a * cnim) >> wp n = 2 while abs(a) > MIN: b = (b*x2) >> wp a = (a*b) >> wp t1 = (cnre*c1re - cnim*c1im - snre*s1re + snim*s1im) >> wp t2 = (cnre*c1im + cnim*c1re - snre*s1im - snim*s1re) >> wp t3 = (snre*c1re - snim*c1im + cnre*s1re - cnim*s1im) >> wp t4 = (snre*c1im + snim*c1re + cnre*s1im + cnim*s1re) >> wp cnre = t1 cnim = t2 snre = t3 snim = t4 if (nd&1): sre += (a * snre * n**nd) >> wp sim += (a * snim * n**nd) >> wp else: sre += (a * cnre * n**nd) >> wp sim += (a * cnim * n**nd) >> wp n += 1 sre = -(sre << (nd+1)) sim = -(sim << (nd+1)) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) # case z and q complex else: wp = mp.prec + extra2 xre, xim = q._mpc_ xre = to_fixed(xre, wp) xim = to_fixed(xim, wp) x2re = (xre*xre - xim*xim) >> wp x2im = (xre*xim) >> (wp - 1) are = bre = xre aim = bim = xim prec0 = mp.prec mp.prec = wp # cos(2*z), sin(2*z) with z complex c1 = cos(2*z) s1 = sin(2*z) mp.prec = prec0 cnre = c1re = to_fixed(c1.real._mpf_, wp) cnim = c1im = to_fixed(c1.imag._mpf_, wp) snre = s1re = to_fixed(s1.real._mpf_, wp) snim = s1im = to_fixed(s1.imag._mpf_, wp) if (nd&1): sre = (are * snre - aim * snim) >> wp sim = (aim * snre + are * snim) >> wp else: sre = (are * cnre - aim * cnim) >> wp sim = (aim * cnre + are * cnim) >> wp n = 2 while are**2 + aim**2 > MIN: bre, bim = (bre * x2re - bim * x2im) >> wp, \ (bre * x2im + bim * x2re) >> wp are, aim = (are * bre - aim * bim) >> wp, \ (are * bim + aim * bre) >> wp t1 = (cnre*c1re - cnim*c1im - snre*s1re + snim*s1im) >> wp t2 = (cnre*c1im + cnim*c1re - snre*s1im - snim*s1re) >> wp t3 = (snre*c1re - snim*c1im + cnre*s1re - cnim*s1im) >> wp t4 = (snre*c1im + snim*c1re + cnre*s1im + cnim*s1re) >> wp cnre = t1 cnim = t2 snre = t3 snim = t4 if(nd&1): sre += ((are * snre - aim * snim) * n**nd) >> wp sim += ((aim * snre + are * snim) * n**nd) >> wp else: sre += ((are * cnre - aim * cnim) * n**nd) >> wp sim += ((aim * cnre + are * cnim) * n**nd) >> wp n += 1 sre = -(sre << (nd+1)) sim = -(sim << (nd+1)) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) if (nd&1): return (-1)**(nd//2) * s else: return (-1)**(1 + nd//2) * s
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 _jacobi_theta2(z, q): extra1 = 10 extra2 = 20 # the loops below break when the fixed precision quantities # a and b go to zero; # right shifting small negative numbers by wp one obtains -1, not zero, # so the condition a**2 + b**2 > MIN is used to break the loops. MIN = 2 if z == zero: if isinstance(q, mpf): wp = mp.prec + extra1 x = to_fixed(q._mpf_, wp) x2 = (x*x) >> wp a = b = x2 s = x2 while abs(a) > MIN: b = (b*x2) >> wp a = (a*b) >> wp s += a s = (1 << (wp+1)) + (s << 1) s = mpf(from_man_exp(s, -wp, mp.prec, 'n')) else: wp = mp.prec + extra1 xre, xim = q._mpc_ xre = to_fixed(xre, wp) xim = to_fixed(xim, wp) x2re = (xre*xre - xim*xim) >> wp x2im = (xre*xim) >> (wp - 1) are = bre = x2re aim = bim = x2im sre = (1<<wp) + are sim = aim while are**2 + aim**2 > MIN: bre, bim = (bre * x2re - bim * x2im) >> wp, \ (bre * x2im + bim * x2re) >> wp are, aim = (are * bre - aim * bim) >> wp, \ (are * bim + aim * bre) >> wp sre += are sim += aim sre = (sre << 1) sim = (sim << 1) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) else: if isinstance(q, mpf) and isinstance(z, mpf): wp = mp.prec + extra1 x = to_fixed(q._mpf_, wp) x2 = (x*x) >> wp a = b = x2 c1, s1 = cos_sin(z._mpf_, wp) cn = c1 = to_fixed(c1, wp) sn = s1 = to_fixed(s1, wp) c2 = (c1*c1 - s1*s1) >> wp s2 = (c1 * s1) >> (wp - 1) cn, sn = (cn*c2 - sn*s2) >> wp, (sn*c2 + cn*s2) >> wp s = c1 + ((a * cn) >> wp) while abs(a) > MIN: b = (b*x2) >> wp a = (a*b) >> wp cn, sn = (cn*c2 - sn*s2) >> wp, (sn*c2 + cn*s2) >> wp s += (a * cn) >> wp s = (s << 1) s = mpf(from_man_exp(s, -wp, mp.prec, 'n')) s *= nthroot(q, 4) return s # case z real, q complex elif isinstance(z, mpf): wp = mp.prec + extra2 xre, xim = q._mpc_ xre = to_fixed(xre, wp) xim = to_fixed(xim, wp) x2re = (xre*xre - xim*xim) >> wp x2im = (xre*xim) >> (wp - 1) are = bre = x2re aim = bim = x2im c1, s1 = cos_sin(z._mpf_, wp) cn = c1 = to_fixed(c1, wp) sn = s1 = to_fixed(s1, wp) c2 = (c1*c1 - s1*s1) >> wp s2 = (c1 * s1) >> (wp - 1) cn, sn = (cn*c2 - sn*s2) >> wp, (sn*c2 + cn*s2) >> wp sre = c1 + ((are * cn) >> wp) sim = ((aim * cn) >> wp) while are**2 + aim**2 > MIN: bre, bim = (bre * x2re - bim * x2im) >> wp, \ (bre * x2im + bim * x2re) >> wp are, aim = (are * bre - aim * bim) >> wp, \ (are * bim + aim * bre) >> wp cn, sn = (cn*c2 - sn*s2) >> wp, (sn*c2 + cn*s2) >> wp sre += ((are * cn) >> wp) sim += ((aim * cn) >> wp) sre = (sre << 1) sim = (sim << 1) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) #case z complex, q real elif isinstance(q, mpf): wp = mp.prec + extra2 x = to_fixed(q._mpf_, wp) x2 = (x*x) >> wp a = b = x2 prec0 = mp.prec mp.prec = wp c1 = cos(z) s1 = sin(z) mp.prec = prec0 cnre = c1re = to_fixed(c1.real._mpf_, wp) cnim = c1im = to_fixed(c1.imag._mpf_, wp) snre = s1re = to_fixed(s1.real._mpf_, wp) snim = s1im = to_fixed(s1.imag._mpf_, wp) #c2 = (c1*c1 - s1*s1) >> wp c2re = (c1re*c1re - c1im*c1im - s1re*s1re + s1im*s1im) >> wp c2im = (c1re*c1im - s1re*s1im) >> (wp - 1) #s2 = (c1 * s1) >> (wp - 1) s2re = (c1re*s1re - c1im*s1im) >> (wp - 1) s2im = (c1re*s1im + c1im*s1re) >> (wp - 1) #cn, sn = (cn*c2 - sn*s2) >> wp, (sn*c2 + cn*s2) >> wp t1 = (cnre*c2re - cnim*c2im - snre*s2re + snim*s2im) >> wp t2 = (cnre*c2im + cnim*c2re - snre*s2im - snim*s2re) >> wp t3 = (snre*c2re - snim*c2im + cnre*s2re - cnim*s2im) >> wp t4 = (snre*c2im + snim*c2re + cnre*s2im + cnim*s2re) >> wp cnre = t1 cnim = t2 snre = t3 snim = t4 sre = c1re + ((a * cnre) >> wp) sim = c1im + ((a * cnim) >> wp) while abs(a) > MIN: b = (b*x2) >> wp a = (a*b) >> wp t1 = (cnre*c2re - cnim*c2im - snre*s2re + snim*s2im) >> wp t2 = (cnre*c2im + cnim*c2re - snre*s2im - snim*s2re) >> wp t3 = (snre*c2re - snim*c2im + cnre*s2re - cnim*s2im) >> wp t4 = (snre*c2im + snim*c2re + cnre*s2im + cnim*s2re) >> wp cnre = t1 cnim = t2 snre = t3 snim = t4 sre += ((a * cnre) >> wp) sim += ((a * cnim) >> wp) sre = (sre << 1) sim = (sim << 1) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) # case z and q complex else: wp = mp.prec + extra2 xre, xim = q._mpc_ xre = to_fixed(xre, wp) xim = to_fixed(xim, wp) x2re = (xre*xre - xim*xim) >> wp x2im = (xre*xim) >> (wp - 1) are = bre = x2re aim = bim = x2im prec0 = mp.prec mp.prec = wp # cos(z), siz(z) with z complex c1 = cos(z) s1 = sin(z) mp.prec = prec0 cnre = c1re = to_fixed(c1.real._mpf_, wp) cnim = c1im = to_fixed(c1.imag._mpf_, wp) snre = s1re = to_fixed(s1.real._mpf_, wp) snim = s1im = to_fixed(s1.imag._mpf_, wp) c2re = (c1re*c1re - c1im*c1im - s1re*s1re + s1im*s1im) >> wp c2im = (c1re*c1im - s1re*s1im) >> (wp - 1) s2re = (c1re*s1re - c1im*s1im) >> (wp - 1) s2im = (c1re*s1im + c1im*s1re) >> (wp - 1) t1 = (cnre*c2re - cnim*c2im - snre*s2re + snim*s2im) >> wp t2 = (cnre*c2im + cnim*c2re - snre*s2im - snim*s2re) >> wp t3 = (snre*c2re - snim*c2im + cnre*s2re - cnim*s2im) >> wp t4 = (snre*c2im + snim*c2re + cnre*s2im + cnim*s2re) >> wp cnre = t1 cnim = t2 snre = t3 snim = t4 n = 1 termre = c1re termim = c1im sre = c1re + ((are * cnre - aim * cnim) >> wp) sim = c1im + ((are * cnim + aim * cnre) >> wp) n = 3 termre = ((are * cnre - aim * cnim) >> wp) termim = ((are * cnim + aim * cnre) >> wp) sre = c1re + ((are * cnre - aim * cnim) >> wp) sim = c1im + ((are * cnim + aim * cnre) >> wp) n = 5 while are**2 + aim**2 > MIN: bre, bim = (bre * x2re - bim * x2im) >> wp, \ (bre * x2im + bim * x2re) >> wp are, aim = (are * bre - aim * bim) >> wp, \ (are * bim + aim * bre) >> wp #cn, sn = (cn*c1 - sn*s1) >> wp, (sn*c1 + cn*s1) >> wp t1 = (cnre*c2re - cnim*c2im - snre*s2re + snim*s2im) >> wp t2 = (cnre*c2im + cnim*c2re - snre*s2im - snim*s2re) >> wp t3 = (snre*c2re - snim*c2im + cnre*s2re - cnim*s2im) >> wp t4 = (snre*c2im + snim*c2re + cnre*s2im + cnim*s2re) >> wp cnre = t1 cnim = t2 snre = t3 snim = t4 termre = ((are * cnre - aim * cnim) >> wp) termim = ((aim * cnre + are * cnim) >> wp) sre += ((are * cnre - aim * cnim) >> wp) sim += ((aim * cnre + are * cnim) >> wp) n += 2 sre = (sre << 1) sim = (sim << 1) sre = from_man_exp(sre, -wp, mp.prec, 'n') sim = from_man_exp(sim, -wp, mp.prec, 'n') s = mpc(sre, sim) s *= nthroot(q, 4) return s
def pslq(x, eps=None): """ Given a vector of real numbers x = [x1, x2, ..., xn], pslq(x) uses the PSLQ algorithm to find a list of integers [c1, c2, ..., cn] such that c1*x1 + c2*x2 + ... + cn*xn = 0 approximately. This is a fairly direct translation to Python of the pseudocode given by David Bailey, "The PSLQ Integer Relation Algorithm": http://www.cecm.sfu.ca/organics/papers/bailey/paper/html/node3.html The stopping criteria are NOT yet properly implemented. Note: now using fixed-point arithmetic for a ~7x speedup compared to the original, pure-mpf version. """ n = len(x) assert n >= 1 prec = mp.prec assert prec >= 53 target = prec // max(2, n) if target < 30: if target < 5: print "Warning: precision for PSLQ may be too low" target = int(prec * 0.75) if eps is None: eps = mpf(2)**(-target) extra = 60 prec += extra eps = to_fixed(eps._mpf_, prec) x = [None] + [to_fixed(mpf(xk)._mpf_, prec) for xk in x] g = sqrt_fixed((4 << prec) // 3, prec) A = {} B = {} H = {} # Initialization # step 1 for i in range(1, n + 1): for j in range(1, n + 1): A[i, j] = B[i, j] = (i == j) << prec H[i, j] = 0 # step 2 s = [None] + [0] * n for k in range(1, n + 1): t = 0 for j in range(k, n + 1): t += (x[j]**2 >> prec) s[k] = sqrt_fixed(t, prec) t = s[1] y = x[:] for k in range(1, n + 1): y[k] = (x[k] << prec) // t s[k] = (s[k] << prec) // t # step 3 for i in range(1, n + 1): for j in range(i + 1, n): H[i, j] = 0 if i <= n - 1: H[i, i] = (s[i + 1] << prec) // s[i] for j in range(1, i): H[i, j] = ((-y[i] * y[j]) << prec) // (s[j] * s[j + 1]) # step 4 for i in range(2, n + 1): for j in range(i - 1, 0, -1): #t = floor(H[i,j]/H[j,j] + 0.5) t = round_fixed((H[i, j] << prec) // H[j, j], prec) y[j] = y[j] + (t * y[i] >> prec) for k in range(1, j + 1): H[i, k] = H[i, k] - (t * H[j, k] >> prec) for k in range(1, n + 1): A[i, k] = A[i, k] - (t * A[j, k] >> prec) B[k, j] = B[k, j] + (t * B[k, i] >> prec) # Main algorithm for REP in range(100): # step 1 m = -1 szmax = -1 for i in range(1, n): h = H[i, i] sz = (sqrt_fixed( (4 << prec) // 3, prec)**i * abs(h)) >> (prec * (i - 1)) if sz > szmax: m = i szmax = sz # step 2 y[m], y[m + 1] = y[m + 1], y[m] tmp = {} for i in range(1, n + 1): H[m, i], H[m + 1, i] = H[m + 1, i], H[m, i] for i in range(1, n + 1): A[m, i], A[m + 1, i] = A[m + 1, i], A[m, i] for i in range(1, n + 1): B[i, m], B[i, m + 1] = B[i, m + 1], B[i, m] # step 3 if m <= n - 2: t0 = sqrt_fixed((H[m, m]**2 + H[m, m + 1]**2) >> prec, prec) # XXX: this could be spurious, due to fixed-point arithmetic if not t0: break t1 = (H[m, m] << prec) // t0 t2 = (H[m, m + 1] << prec) // t0 for i in range(m, n + 1): t3 = H[i, m] t4 = H[i, m + 1] H[i, m] = (t1 * t3 + t2 * t4) >> prec H[i, m + 1] = (-t2 * t3 + t1 * t4) >> prec # step 4 for i in range(m + 1, n + 1): for j in range(min(i - 1, m + 1), 0, -1): try: t = round_fixed((H[i, j] << prec) // H[j, j], prec) # XXX except ZeroDivisionError: break y[j] = y[j] + ((t * y[i]) >> prec) for k in range(1, j + 1): H[i, k] = H[i, k] - (t * H[j, k] >> prec) for k in range(1, n + 1): A[i, k] = A[i, k] - (t * A[j, k] >> prec) B[k, j] = B[k, j] + (t * B[k, i] >> prec) for i in range(1, n + 1): if abs(y[i]) < eps: vec = [ int(round_fixed(B[j, i], prec) >> prec) for j in range(1, n + 1) ] if max(abs(v) for v in vec) < 10**6: return vec return None
def pslq(x, tol=None, maxcoeff=1000, maxsteps=100, verbose=False): r""" Given a vector of real numbers `x = [x_0, x_1, ..., x_n]`, ``pslq(x)`` uses the PSLQ algorithm to find a list of integers `[c_0, c_1, ..., c_n]` such that .. math :: |c_1 x_1 + c_2 x_2 + ... + c_n x_n| < \mathrm{tol} and such that `\max |c_k| < \mathrm{maxcoeff}`. If no such vector exists, :func:`pslq` returns ``None``. The tolerance defaults to 3/4 of the working precision. **Examples** Find rational approximations for `\pi`:: >>> from mpmath import * >>> mp.dps = 15 >>> pslq([pi, 1], tol=0.01) [-7, 22] >>> pslq([pi, 1], tol=0.001) [113, -355] Pi is not a rational number with denominator less than 1000:: >>> pslq([pi, 1]) >>> To within the standard precision, it can however be approximated by at least one rational number with denominator less than `10^{12}`:: >>> pslq([pi, 1], maxcoeff=10**12) [-75888275702L, 238410049439L] >>> print mpf(_[1])/_[0] -3.14159265358979 The PSLQ algorithm can be applied to long vectors. For example, we can investigate the rational (in)dependence of integer square roots:: >>> mp.dps = 30 >>> pslq([sqrt(n) for n in range(2, 5+1)]) >>> >>> pslq([sqrt(n) for n in range(2, 6+1)]) >>> >>> pslq([sqrt(n) for n in range(2, 8+1)]) [2, 0, 0, 0, 0, 0, -1] **Machin formulas** A famous formula for `\pi` is Machin's, .. math :: \frac{\pi}{4} = 4 \operatorname{acot} 5 - \operatorname{acot} 239 There are actually infinitely many formulas of this type. Two others are .. math :: \frac{\pi}{4} = \operatorname{acot} 1 \frac{\pi}{4} = 12 \operatorname{acot} 49 + 32 \operatorname{acot} 57 + 5 \operatorname{acot} 239 + 12 \operatorname{acot} 110443 We can easily verify the formulas using the PSLQ algorithm:: >>> mp.dps = 30 >>> pslq([pi/4, acot(1)]) [1, -1] >>> pslq([pi/4, acot(5), acot(239)]) [1, -4, 1] >>> pslq([pi/4, acot(49), acot(57), acot(239), acot(110443)]) [1, -12, -32, 5, -12] We could try to generate a custom Machin-like formula by running the PSLQ algorithm with a few inverse cotangent values, for example acot(2), acot(3) ... acot(10). Unfortunately, there is a linear dependence among these values, resulting in only that dependence being detected, with a zero coefficient for `\pi`:: >>> pslq([pi] + [acot(n) for n in range(2,11)]) [0, 1, -1, 0, 0, 0, -1, 0, 0, 0] We get better luck by removing linearly dependent terms:: >>> pslq([pi] + [acot(n) for n in range(2,11) if n not in (3, 5)]) [1, -8, 0, 0, 4, 0, 0, 0] In other words, we found the following formula:: >>> print 8*acot(2) - 4*acot(7) 3.14159265358979323846264338328 >>> print pi 3.14159265358979323846264338328 **Algorithm** This is a fairly direct translation to Python of the pseudocode given by David Bailey, "The PSLQ Integer Relation Algorithm": http://www.cecm.sfu.ca/organics/papers/bailey/paper/html/node3.html The present implementation uses fixed-point instead of floating-point arithmetic, since this is significantly (about 7x) faster. """ n = len(x) assert n >= 2 # At too low precision, the algorithm becomes meaningless prec = mp.prec assert prec >= 53 if verbose and prec // max(2, n) < 5: print "Warning: precision for PSLQ may be too low" target = int(prec * 0.75) if tol is None: tol = mpf(2)**(-target) else: tol = mpmathify(tol) extra = 60 prec += extra if verbose: print "PSLQ using prec %i and tol %s" % (prec, nstr(tol)) tol = to_fixed(tol._mpf_, prec) assert tol # Convert to fixed-point numbers. The dummy None is added so we can # use 1-based indexing. (This just allows us to be consistent with # Bailey's indexing. The algorithm is 100 lines long, so debugging # a single wrong index can be painful.) x = [None] + [to_fixed(mpf(xk)._mpf_, prec) for xk in x] # Sanity check on magnitudes minx = min(abs(xx) for xx in x[1:]) if not minx: raise ValueError("PSLQ requires a vector of nonzero numbers") if minx < tol // 100: if verbose: print "STOPPING: (one number is too small)" return None g = sqrt_fixed((4 << prec) // 3, prec) A = {} B = {} H = {} # Initialization # step 1 for i in xrange(1, n + 1): for j in xrange(1, n + 1): A[i, j] = B[i, j] = (i == j) << prec H[i, j] = 0 # step 2 s = [None] + [0] * n for k in xrange(1, n + 1): t = 0 for j in xrange(k, n + 1): t += (x[j]**2 >> prec) s[k] = sqrt_fixed(t, prec) t = s[1] y = x[:] for k in xrange(1, n + 1): y[k] = (x[k] << prec) // t s[k] = (s[k] << prec) // t # step 3 for i in xrange(1, n + 1): for j in xrange(i + 1, n): H[i, j] = 0 if i <= n - 1: if s[i]: H[i, i] = (s[i + 1] << prec) // s[i] else: H[i, i] = 0 for j in range(1, i): sjj1 = s[j] * s[j + 1] if sjj1: H[i, j] = ((-y[i] * y[j]) << prec) // sjj1 else: H[i, j] = 0 # step 4 for i in xrange(2, n + 1): for j in xrange(i - 1, 0, -1): #t = floor(H[i,j]/H[j,j] + 0.5) if H[j, j]: t = round_fixed((H[i, j] << prec) // H[j, j], prec) else: #t = 0 continue y[j] = y[j] + (t * y[i] >> prec) for k in xrange(1, j + 1): H[i, k] = H[i, k] - (t * H[j, k] >> prec) for k in xrange(1, n + 1): A[i, k] = A[i, k] - (t * A[j, k] >> prec) B[k, j] = B[k, j] + (t * B[k, i] >> prec) # Main algorithm for REP in range(maxsteps): # Step 1 m = -1 szmax = -1 for i in range(1, n): h = H[i, i] sz = (sqrt_fixed( (4 << prec) // 3, prec)**i * abs(h)) >> (prec * (i - 1)) if sz > szmax: m = i szmax = sz # Step 2 y[m], y[m + 1] = y[m + 1], y[m] tmp = {} for i in xrange(1, n + 1): H[m, i], H[m + 1, i] = H[m + 1, i], H[m, i] for i in xrange(1, n + 1): A[m, i], A[m + 1, i] = A[m + 1, i], A[m, i] for i in xrange(1, n + 1): B[i, m], B[i, m + 1] = B[i, m + 1], B[i, m] # Step 3 if m <= n - 2: t0 = sqrt_fixed((H[m, m]**2 + H[m, m + 1]**2) >> prec, prec) # A zero element probably indicates that the precision has # been exhausted. XXX: this could be spurious, due to # using fixed-point arithmetic if not t0: break t1 = (H[m, m] << prec) // t0 t2 = (H[m, m + 1] << prec) // t0 for i in xrange(m, n + 1): t3 = H[i, m] t4 = H[i, m + 1] H[i, m] = (t1 * t3 + t2 * t4) >> prec H[i, m + 1] = (-t2 * t3 + t1 * t4) >> prec # Step 4 for i in xrange(m + 1, n + 1): for j in xrange(min(i - 1, m + 1), 0, -1): try: t = round_fixed((H[i, j] << prec) // H[j, j], prec) # Precision probably exhausted except ZeroDivisionError: break y[j] = y[j] + ((t * y[i]) >> prec) for k in xrange(1, j + 1): H[i, k] = H[i, k] - (t * H[j, k] >> prec) for k in xrange(1, n + 1): A[i, k] = A[i, k] - (t * A[j, k] >> prec) B[k, j] = B[k, j] + (t * B[k, i] >> prec) # Until a relation is found, the error typically decreases # slowly (e.g. a factor 1-10) with each step TODO: we could # compare err from two successive iterations. If there is a # large drop (several orders of magnitude), that indicates a # "high quality" relation was detected. Reporting this to # the user somehow might be useful. best_err = maxcoeff << prec for i in xrange(1, n + 1): err = abs(y[i]) # Maybe we are done? if err < tol: # We are done if the coefficients are acceptable vec = [int(round_fixed(B[j,i], prec) >> prec) for j in \ range(1,n+1)] if max(abs(v) for v in vec) < maxcoeff: if verbose: print "FOUND relation at iter %i/%i, error: %s" % \ (REP, maxsteps, nstr(err / mpf(2)**prec, 1)) return vec best_err = min(err, best_err) # Calculate a lower bound for the norm. We could do this # more exactly (using the Euclidean norm) but there is probably # no practical benefit. recnorm = max(abs(h) for h in H.values()) if recnorm: norm = ((1 << (2 * prec)) // recnorm) >> prec norm //= 100 else: norm = inf if verbose: print "%i/%i: Error: %8s Norm: %s" % \ (REP, maxsteps, nstr(best_err / mpf(2)**prec, 1), norm) if norm >= maxcoeff: break if verbose: print "CANCELLING after step %i/%i." % (REP, maxsteps) print "Could not find an integer relation. Norm bound: %s" % norm return None