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 = 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 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 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 = int(r * 2.0**53) >> (53-prevp) extra_p = 100 for p in giant_steps(prevp, prec): s = int(0.137 * p**0.579) p += s + 50 r = r << (p-prevp) cos, sin = expi_series(r, p, s) tan = (sin << p) // cos a = ((tan - rshift(x, prec-p)) << p) // ((MP_ONE<<p) + ((tan**2)>>p)) r = r - a prevp = p return rshift(r, prevp-prec)
def nthroot_fixed(y, n, prec, exp1): start = 50 try: y1 = rshift(y, prec - n*start) r = MP_BASE(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 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 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 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 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 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 mpf_log(x, prec, rnd=round_fast): """ Compute the natural logarithm of the mpf value x. If x is negative, ComplexResult is raised. """ sign, man, exp, bc = x if not man: if x == fzero: return fninf if x == finf: return finf if x == fnan: return fnan if sign: raise ComplexResult("logarithm of a negative number") # log(2^n) if man == 1: if not exp: return fzero return from_man_exp(exp*ln2_fixed(prec+20), -prec-20, prec, rnd) # Assume 20 bits to be sufficient for cancelling rounding errors wp = prec + 20 mag = bc + exp # Already on the standard interval, (0.5, 1) if not mag: t = rshift(man, bc-wp) log2n = 0 # Watch out for "x = 0.9999" # Proceed only if 1-x lost at most 15 bits of accuracy res = (MP_ONE << wp) - t if not (res >> (wp - 15)): # Find out extra precision needed delta = mpf_sub(x, fone, 10) delta_bits = -(delta[2] + delta[3]) # O(x^2) term vanishes relatively if delta_bits > wp + 10: xm1 = mpf_sub(x, fone, prec, rnd) return mpf_perturb(xm1, 1, prec, rnd) else: wp += delta_bits t = rshift(man, bc-wp) # Already on the standard interval, (1, 2) elif mag == 1: t = rshift(man, bc-wp-1) log2n = 0 # Watch out for "x = 1.0001" # Similar to above; note that we flip signs # to obtain a positive residual, ensuring that # the following shift rounds down res = t - (MP_ONE << wp) if not (res >> (wp - 15)): # Find out extra precision needed delta = mpf_sub(x, fone, 10) delta_bits = -(delta[2] + delta[3]) # O(x^2) term vanishes relatively if delta_bits > wp + 10: xm1 = mpf_sub(x, fone, prec, rnd) return mpf_perturb(xm1, 1, prec, rnd) else: wp += delta_bits t = rshift(man, bc-wp-1) # Rescale else: # Estimated precision needed for n*log(2) to # be accurate relatively wp += int(math.log(1+abs(mag),2)) log2n = mag * ln2_fixed(wp) # Rescaled argument as a fixed-point number t = rshift(man, bc-wp) # Use the faster method if wp < LOG_TAYLOR_PREC: a = log_taylor(t, wp) else: a = log_newton(t, wp) return from_man_exp(a + log2n, -wp, prec, rnd)
def mpf_nthroot(s, n, prec, rnd=round_fast): """nth-root of a positive number Use the Newton method when faster, otherwise use x**(1/n) """ sign, man, exp, bc = s if sign: raise ComplexResult("nth root of a negative number") if not man: if s == fnan: return fnan if s == fzero: if n > 0: return fzero if n == 0: return fone return finf # Infinity if not n: return fnan if n < 0: return fzero return finf flag_inverse = False if n < 2: if n == 0: return fone if n == 1: return mpf_pos(s, prec, rnd) if n == -1: return mpf_div(fone, s, prec, rnd) # n < 0 rnd = reciprocal_rnd[rnd] flag_inverse = True extra_inverse = 5 prec += extra_inverse n = -n if n > 20 and (n >= 20000 or prec < int(233 + 28.3 * n**0.62)): prec2 = prec + 10 fn = from_int(n) nth = mpf_rdiv_int(1, fn, prec2) r = mpf_pow(s, nth, prec2, rnd) s = normalize(r[0], r[1], r[2], r[3], prec, rnd) if flag_inverse: return mpf_div(fone, s, prec-extra_inverse, rnd) else: return s # Convert to a fixed-point number with prec2 bits. prec2 = prec + 2*n - (prec%n) # a few tests indicate that # for 10 < n < 10**4 a bit more precision is needed if n > 10: prec2 += prec2//10 prec2 = prec2 - prec2%n # Mantissa may have more bits than we need. Trim it down. shift = bc - prec2 # Adjust exponents to make prec2 and exp+shift multiples of n. sign1 = 0 es = exp+shift if es < 0: sign1 = 1 es = -es if sign1: shift += es%n else: shift -= es%n man = rshift(man, shift) extra = 10 exp1 = ((exp+shift-(n-1)*prec2)//n) - extra rnd_shift = 0 if flag_inverse: if rnd == 'u' or rnd == 'c': rnd_shift = 1 else: if rnd == 'd' or rnd == 'f': rnd_shift = 1 man = nthroot_fixed(man+rnd_shift, n, prec2, exp1) s = from_man_exp(man, exp1, prec, rnd) if flag_inverse: return mpf_div(fone, s, prec-extra_inverse, rnd) else: return s
def mpf_log(x, prec, rnd=round_fast): """ Compute the natural logarithm of the mpf value x. If x is negative, ComplexResult is raised. """ sign, man, exp, bc = x if not man: if x == fzero: return fninf if x == finf: return finf if x == fnan: return fnan if sign: raise ComplexResult("logarithm of a negative number") # log(2^n) if man == 1: if not exp: return fzero return from_man_exp(exp * ln2_fixed(prec + 20), -prec - 20, prec, rnd) # Assume 20 bits to be sufficient for cancelling rounding errors wp = prec + 20 mag = bc + exp # Already on the standard interval, (0.5, 1) if not mag: t = rshift(man, bc - wp) log2n = 0 # Watch out for "x = 0.9999" # Proceed only if 1-x lost at most 15 bits of accuracy res = (MP_ONE << wp) - t if not (res >> (wp - 15)): # Find out extra precision needed delta = mpf_sub(x, fone, 10) delta_bits = -(delta[2] + delta[3]) # O(x^2) term vanishes relatively if delta_bits > wp + 10: xm1 = mpf_sub(x, fone, prec, rnd) return mpf_perturb(xm1, 1, prec, rnd) else: wp += delta_bits t = rshift(man, bc - wp) # Already on the standard interval, (1, 2) elif mag == 1: t = rshift(man, bc - wp - 1) log2n = 0 # Watch out for "x = 1.0001" # Similar to above; note that we flip signs # to obtain a positive residual, ensuring that # the following shift rounds down res = t - (MP_ONE << wp) if not (res >> (wp - 15)): # Find out extra precision needed delta = mpf_sub(x, fone, 10) delta_bits = -(delta[2] + delta[3]) # O(x^2) term vanishes relatively if delta_bits > wp + 10: xm1 = mpf_sub(x, fone, prec, rnd) return mpf_perturb(xm1, 1, prec, rnd) else: wp += delta_bits t = rshift(man, bc - wp - 1) # Rescale else: # Estimated precision needed for n*log(2) to # be accurate relatively wp += int(math.log(1 + abs(mag), 2)) log2n = mag * ln2_fixed(wp) # Rescaled argument as a fixed-point number t = rshift(man, bc - wp) # Use the faster method if wp < LOG_TAYLOR_PREC: a = log_taylor(t, wp) else: a = log_newton(t, wp) return from_man_exp(a + log2n, -wp, prec, rnd)