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 = MP_ZERO for a, b in coefs: s += MP_BASE(a) * acot_fixed(MP_BASE(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 = MP_BASE(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 = MP_BASE(man) sign = 0 if man < 0: man = -man sign = 1 bc = bitcount(man) return normalize(sign, man, exp, bc, bc, round_floor)
def sin_taylor(x, prec): x = MP_BASE(x) x2 = (x*x) >> prec s = a = x k = 3 while a: a = ((a * x2) >> prec) // (k*(1-k)) s += a k += 2 return s
def cos_taylor(x, prec): x = MP_BASE(x) x2 = (x*x) >> prec a = c = (MP_ONE<<prec) k = 2 while a: a = ((a * x2) >> prec) // (k*(1-k)) c += a k += 2 return c
def bsp_acot(q, a, b, hyperbolic): if b - a == 1: a1 = MP_BASE(2*a + 3) if hyperbolic or a&1: return MP_ONE, a1 * q**2, a1 else: return -MP_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 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 MP_ONE, MP_BASE(b) m = (a+b)//2 p1, q1 = bspe(a, m) p2, q2 = bspe(m, b) return p1*q2+p2, q1*q2
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 # XXX: workaround bug in gmpy if abs(re) < 0.1: re = 0 if abs(im) < 0.1: im = 0 re = MP_BASE(re) im = MP_BASE(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 apery_fixed(prec): prec += 20 d = MP_ONE << prec term = MP_BASE(77) << prec n = 1 s = MP_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 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 < 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 // (MP_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 = MP_ZERO s = MP_BASE(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))) return from_man_exp(t, -wp - wp, prec, rnd)
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 = MP_BASE(int(x, base)) return x, exp
def nthroot_fixed(y, n, prec, exp1): start = 50 try: y1 = rshift(y, prec - n*start) r = MP_BASE(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 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 = MP_BASE((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 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, MP_BASE(base)**half) ad = numeral(A, base, half, digits) bd = numeral(B, base, half, digits).rjust(half, "0") return ad + bd
def log_newton(x, prec): extra = 10 # 40-bit approximation fx = math.log(long(x)) - 0.69314718055994529 * prec r = MP_BASE(fx * 2.0**40) prevp = 40 for p in giant_steps2(40, prec + extra): rb = lshift(r, p - prevp) # Parameters for exponential series if p < 300: r = int(2 * p**0.4) exp_func = exp_series else: r = int(0.7 * p**0.5) exp_func = exp_series2 exp_extra = r + 10 e = exp_func((-rb) << exp_extra, p + exp_extra, r) s = ((rshift(x, prec - p) * e) >> (p + exp_extra)) - (1 << p) s1 = -((s * s) >> (p + 1)) r = rb + s + s1 prevp = p return r >> extra
def acot_fixed(n, prec, hyperbolic): """ Compute acot of an integer using fixed-point arithmetic. With hyperbolic=True, compute acoth. The standard Taylor series is used. """ n = MP_BASE(n) s = t = (MP_ONE << prec) // n # 1 / n k = 3 while 1: # Repeatedly divide by k * n**2, and add t //= (n * n) term = t // k if not term: break # Alternate signs if hyperbolic or not k & 2: s += term else: s -= term k += 2 return s
def __new__(cls, val=fzero, **kwargs): """A new mpf can be created from a Python float, an int, a or a decimal string representing a number in floating-point format.""" prec, rounding = prec_rounding if kwargs: prec = kwargs.get('prec', prec) if 'dps' in kwargs: prec = dps_to_prec(kwargs['dps']) rounding = kwargs.get('rounding', rounding) if type(val) is cls: sign, man, exp, bc = val._mpf_ if (not man) and exp: return val return make_mpf(normalize(sign, man, exp, bc, prec, rounding)) elif type(val) is tuple: if len(val) == 2: return make_mpf(from_man_exp(val[0], val[1], prec, rounding)) if len(val) == 4: sign, man, exp, bc = val return make_mpf(normalize(sign, MP_BASE(man), exp, bc, prec, rounding)) raise ValueError else: return make_mpf(mpf_pos(mpf_convert_arg(val, prec, rounding), prec, rounding))
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]
def from_pickable(x): sign, man, exp, bc = x return (sign, MP_BASE(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 MODE == 'gmpy': isqrt_small = isqrt_fast = isqrt = gmpy.sqrt sqrtrem = gmpy.sqrtrem elif MODE == 'sage': isqrt_small = isqrt_fast = isqrt = lambda n: MP_BASE(n).isqrt() sqrtrem = lambda n: MP_BASE(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]
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 = MP_BASE(13591409) CHUD_B = MP_BASE(545140134) CHUD_C = MP_BASE(640320) CHUD_D = MP_BASE(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 = MP_BASE((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)
def sage_bitcount(n): if n: return MP_BASE(n).nbits() else: return 0
def gmpy_bitcount(n): """Calculate bit size of the nonnegative integer n.""" if n: return MP_BASE(n).numdigits(2) else: return 0
def gmpy_trailing(n): """Count the number of trailing zero bits in abs(n) using gmpy.""" if n: return MP_BASE(n).scan1() else: return 0
def sage_trailing(n): return MP_BASE(n).trailing_zero_bits()
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 * (MP_BASE(base)**bdigits) >> xbits