def machin(coefs, prec, hyperbolic=False): """ Evaluate a Machin-like formula, i.e., a linear combination of acot(n) or acoth(n) for specific integer values of n, using fixed- point arithmetic. The input should be a list [(c, n), ...], giving c*acot[h](n) + ... """ extraprec = 10 s = MPZ_ZERO for a, b in coefs: s += MPZ(a) * acot_fixed(MPZ(b), prec + extraprec, hyperbolic) return (s >> extraprec)
def from_man_exp(man, exp, prec=None, rnd=round_fast): """Create raw mpf from (man, exp) pair. The mantissa may be signed. If no precision is specified, the mantissa is stored exactly.""" man = MPZ(man) sign = 0 if man < 0: sign = 1 man = -man if man < 1024: bc = bctable[int(man)] else: bc = bitcount(man) if not prec: if not man: return fzero if not man & 1: if man & 2: return (sign, man >> 1, exp + 1, bc - 1) t = trailtable[int(man & 255)] if not t: while not man & 255: man >>= 8 exp += 8 bc -= 8 t = trailtable[int(man & 255)] man >>= t exp += t bc -= t return (sign, man, exp, bc) return normalize(sign, man, exp, bc, prec, rnd)
def from_bstr(x): man, exp = str_to_man_exp(x, base=2) man = MPZ(man) sign = 0 if man < 0: man = -man sign = 1 bc = bitcount(man) return normalize(sign, man, exp, bc, bc, round_floor)
def stirling2(n, k): """ Stirling number of the second kind. """ if n < 0 or k < 0: raise ValueError if k >= n: return MPZ(n == k) if k <= 1: return MPZ(k == 1) s = MPZ_ZERO t = MPZ_ONE for j in xrange(k + 1): if (k + j) & 1: s -= t * MPZ(j)**n else: s += t * MPZ(j)**n t = t * (k - j) // (j + 1) return s // ifac(k)
def bspe(a, b): """ Sum series for exp(1)-1 between a, b, returning the result as an exact fraction (p, q). """ if b - a == 1: return MPZ_ONE, MPZ(b) m = (a + b) // 2 p1, q1 = bspe(a, m) p2, q2 = bspe(m, b) return p1 * q2 + p2, q1 * q2
def bsp_acot(q, a, b, hyperbolic): if b - a == 1: a1 = MPZ(2 * a + 3) if hyperbolic or a & 1: return MPZ_ONE, a1 * q**2, a1 else: return -MPZ_ONE, a1 * q**2, a1 m = (a + b) // 2 p1, q1, r1 = bsp_acot(q, a, m, hyperbolic) p2, q2, r2 = bsp_acot(q, m, b, hyperbolic) return q2 * p1 + r1 * p2, q1 * q2, r1 * r2
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 apery_fixed(prec): prec += 20 d = MPZ_ONE << prec term = MPZ(77) << prec n = 1 s = MPZ_ZERO while term: s += term d *= (n**10) d //= (((2 * n + 1)**5) * (2 * n)**5) term = (-1)**n * (205 * (n**2) + 250 * n + 77) * d n += 1 return s >> (20 + 6)
def mpc_nthroot_fixed(a, b, n, prec): # a, b signed integers at fixed precision prec start = 50 a1 = int(rshift(a, prec - n * start)) b1 = int(rshift(b, prec - n * start)) try: r = (a1 + 1j * b1)**(1.0 / n) re = r.real im = r.imag re = MPZ(int(re)) im = MPZ(int(im)) except OverflowError: a1 = from_int(a1, start) b1 = from_int(b1, start) fn = from_int(n) nth = mpf_rdiv_int(1, fn, start) re, im = mpc_pow((a1, b1), (nth, fzero), start) re = to_int(re) im = to_int(im) extra = 10 prevp = start extra1 = n for p in giant_steps(start, prec + extra): # this is slow for large n, unlike int_pow_fixed re2, im2 = complex_int_pow(re, im, n - 1) re2 = rshift(re2, (n - 1) * prevp - p - extra1) im2 = rshift(im2, (n - 1) * prevp - p - extra1) r4 = (re2 * re2 + im2 * im2) >> (p + extra1) ap = rshift(a, prec - p) bp = rshift(b, prec - p) rec = (ap * re2 + bp * im2) >> p imc = (-ap * im2 + bp * re2) >> p reb = (rec << p) // r4 imb = (imc << p) // r4 re = (reb + (n - 1) * lshift(re, p - prevp)) // n im = (imb + (n - 1) * lshift(im, p - prevp)) // n prevp = p return re, im
def stirling1(n, k): """ Stirling number of the first kind. """ if n < 0 or k < 0: raise ValueError if k >= n: return MPZ(n == k) if k < 1: return MPZ_ZERO L = [MPZ_ZERO] * (k + 1) L[1] = MPZ_ONE for m in xrange(2, n + 1): for j in xrange(min(k, m), 0, -1): L[j] = (m - 1) * L[j] + L[j - 1] return (-1)**(n + k) * L[k]
def atan_newton(x, prec): if prec >= 100: r = math.atan((x >> (prec - 53)) / 2.0**53) else: r = math.atan(x / 2.0**prec) prevp = 50 r = MPZ(int(r * 2.0**53) >> (53 - prevp)) extra_p = 50 for wp in giant_steps(prevp, prec): wp += extra_p r = r << (wp - prevp) cos, sin = cos_sin_fixed(r, wp) tan = (sin << wp) // cos a = ((tan - rshift(x, prec - wp)) << wp) // ((MPZ_ONE << wp) + ((tan**2) >> wp)) r = r - a prevp = wp return rshift(r, prevp - prec)
def str_to_man_exp(x, base=10): """Helper function for from_str.""" # Verify that the input is a valid float literal float(x) # Split into mantissa, exponent x = x.lower() parts = x.split('e') if len(parts) == 1: exp = 0 else: # == 2 x = parts[0] exp = int(parts[1]) # Look for radix point in mantissa parts = x.split('.') if len(parts) == 2: a, b = parts[0], parts[1].rstrip('0') exp -= len(b) x = a + b x = MPZ(int(x, base)) return x, exp
def numeral_gmpy(n, base=10, size=0, digits=stddigits): """Represent the integer n as a string of digits in the given base. Recursive division is used to make this function about 3x faster than Python's str() for converting integers to decimal strings. The 'size' parameters specifies the number of digits in n; this number is only used to determine splitting points and need not be exact.""" if n < 0: return "-" + numeral(-n, base, size, digits) # gmpy.digits() may cause a segmentation fault when trying to convert # extremely large values to a string. The size limit may need to be # adjusted on some platforms, but 1500000 works on Windows and Linux. if size < 1500000: return gmpy.digits(n, base) # Divide in half half = (size // 2) + (size & 1) A, B = divmod(n, MPZ(base)**half) ad = numeral(A, base, half, digits) bd = numeral(B, base, half, digits).rjust(half, "0") return ad + bd
def bs_chudnovsky(a, b, level, verbose): """ Computes the sum from a to b of the series in the Chudnovsky formula. Returns g, p, q where p/q is the sum as an exact fraction and g is a temporary value used to save work for recursive calls. """ if b - a == 1: g = MPZ((6 * b - 5) * (2 * b - 1) * (6 * b - 1)) p = b**3 * CHUD_C**3 // 24 q = (-1)**b * g * (CHUD_A + CHUD_B * b) else: if verbose and level < 4: print " binary splitting", a, b mid = (a + b) // 2 g1, p1, q1 = bs_chudnovsky(a, mid, level + 1, verbose) g2, p2, q2 = bs_chudnovsky(mid, b, level + 1, verbose) p = p1 * p2 g = g1 * g2 q = q1 * p2 + q2 * g1 return g, p, q
def nthroot_fixed(y, n, prec, exp1): start = 50 try: y1 = rshift(y, prec - n * start) r = MPZ(int(y1**(1.0 / n))) except OverflowError: y1 = from_int(y1, start) fn = from_int(n) fn = mpf_rdiv_int(1, fn, start) r = mpf_pow(y1, fn, start) r = to_int(r) extra = 10 extra1 = n prevp = start for p in giant_steps(start, prec + extra): pm, pe = int_pow_fixed(r, n - 1, prevp) r2 = rshift(pm, (n - 1) * prevp - p - pe - extra1) B = lshift(y, 2 * p - prec + extra1) // r2 r = (B + (n - 1) * lshift(r, p - prevp)) // n prevp = p return r
def eulernum(m, _cache={0: MPZ_ONE}): r""" Computes the Euler numbers `E(n)`, which can be defined as coefficients of the Taylor expansion of `1/cosh x`: .. math :: \frac{1}{\cosh x} = \sum_{n=0}^\infty \frac{E_n}{n!} x^n Example:: >>> [int(eulernum(n)) for n in range(11)] [1, 0, -1, 0, 5, 0, -61, 0, 1385, 0, -50521] >>> [int(eulernum(n)) for n in range(11)] # test cache [1, 0, -1, 0, 5, 0, -61, 0, 1385, 0, -50521] """ # for odd m > 1, the Euler numbers are zero if m & 1: return MPZ_ZERO f = _cache.get(m) if f: return f MAX = MAX_EULER_CACHE n = m a = [MPZ(_) for _ in [0, 0, 1, 0, 0, 0]] for n in range(1, m + 1): for j in range(n + 1, -1, -2): a[j + 1] = (j - 1) * a[j] + (j + 1) * a[j + 2] a.append(0) suma = 0 for k in range(n + 1, -1, -2): suma += a[k + 1] if n <= MAX: _cache[n] = ((-1)**(n // 2)) * (suma // 2**n) if n == m: return ((-1)**(n // 2)) * suma // 2**n
def sqrt_fixed(x, prec): return isqrt_fast(x << prec) sqrt_fixed2 = sqrt_fixed if BACKEND == 'gmpy': if gmpy.version() >= '2': isqrt_small = isqrt_fast = isqrt = gmpy.isqrt sqrtrem = gmpy.isqrt_rem else: isqrt_small = isqrt_fast = isqrt = gmpy.sqrt sqrtrem = gmpy.sqrtrem elif BACKEND == 'sage': isqrt_small = isqrt_fast = isqrt = \ getattr(sage_utils, "isqrt", lambda n: MPZ(n).isqrt()) sqrtrem = lambda n: MPZ(n).sqrtrem() else: isqrt_small = isqrt_small_python isqrt_fast = isqrt_fast_python isqrt = isqrt_python sqrtrem = sqrtrem_python def ifib(n, _cache={}): """Computes the nth Fibonacci number as an integer, for integer n.""" if n < 0: return (-1)**(-n + 1) * ifib(-n) if n in _cache: return _cache[n]
def gmpy_trailing(n): """Count the number of trailing zero bits in abs(n) using gmpy.""" if n: return MPZ(n).scan1() else: return 0
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]
series contains only rational terms. This makes binary splitting very efficient. The recurrence formulas for the binary splitting were taken from ftp://ftp.gmplib.org/pub/src/gmp-chudnovsky.c Previously, Machin's formula was used at low precision and the AGM iteration was used at high precision. However, the Chudnovsky series is essentially as fast as the Machin formula at low precision and in practice about 3x faster than the AGM at high precision (despite theoretically having a worse asymptotic complexity), so there is no reason not to use it in all cases. """ # Constants in Chudnovsky's series CHUD_A = MPZ(13591409) CHUD_B = MPZ(545140134) CHUD_C = MPZ(640320) CHUD_D = MPZ(12) def bs_chudnovsky(a, b, level, verbose): """ Computes the sum from a to b of the series in the Chudnovsky formula. Returns g, p, q where p/q is the sum as an exact fraction and g is a temporary value used to save work for recursive calls. """ if b - a == 1: g = MPZ((6 * b - 5) * (2 * b - 1) * (6 * b - 1)) p = b**3 * CHUD_C**3 // 24
def bin_to_radix(x, xbits, base, bdigits): """Changes radix of a fixed-point number; i.e., converts x * 2**xbits to floor(x * 10**bdigits).""" return x * (MPZ(base)**bdigits) >> xbits
def sage_trailing(n): return MPZ(n).trailing_zero_bits()
def gmpy_bitcount(n): """Calculate bit size of the nonnegative integer n.""" if n: return MPZ(n).numdigits(2) else: return 0
def from_pickable(x): sign, man, exp, bc = x return (sign, MPZ(man, 16), exp, bc)
def isqrt_python(x): """Integer square root with correct (floor) rounding.""" return sqrtrem_python(x)[0] def sqrt_fixed(x, prec): return isqrt_fast(x << prec) sqrt_fixed2 = sqrt_fixed if BACKEND == 'gmpy': isqrt_small = isqrt_fast = isqrt = gmpy.sqrt sqrtrem = gmpy.sqrtrem elif BACKEND == 'sage': isqrt_small = isqrt_fast = isqrt = lambda n: MPZ(n).isqrt() sqrtrem = lambda n: MPZ(n).sqrtrem() else: isqrt_small = isqrt_small_python isqrt_fast = isqrt_fast_python isqrt = isqrt_python sqrtrem = sqrtrem_python def ifib(n, _cache={}): """Computes the nth Fibonacci number as an integer, for integer n.""" if n < 0: return (-1)**(-n + 1) * ifib(-n) if n in _cache: return _cache[n]