| from .ctx_base import StandardBaseContext |
|
|
| import math |
| import cmath |
| from . import math2 |
|
|
| from . import function_docs |
|
|
| from .libmp import mpf_bernoulli, to_float, int_types |
| from . import libmp |
|
|
| class FPContext(StandardBaseContext): |
| """ |
| Context for fast low-precision arithmetic (53-bit precision, giving at most |
| about 15-digit accuracy), using Python's builtin float and complex. |
| """ |
|
|
| def __init__(ctx): |
| StandardBaseContext.__init__(ctx) |
|
|
| |
| ctx.loggamma = math2.loggamma |
| ctx._bernoulli_cache = {} |
| ctx.pretty = False |
|
|
| ctx._init_aliases() |
|
|
| _mpq = lambda cls, x: float(x[0])/x[1] |
|
|
| NoConvergence = libmp.NoConvergence |
|
|
| def _get_prec(ctx): return 53 |
| def _set_prec(ctx, p): return |
| def _get_dps(ctx): return 15 |
| def _set_dps(ctx, p): return |
|
|
| _fixed_precision = True |
|
|
| prec = property(_get_prec, _set_prec) |
| dps = property(_get_dps, _set_dps) |
|
|
| zero = 0.0 |
| one = 1.0 |
| eps = math2.EPS |
| inf = math2.INF |
| ninf = math2.NINF |
| nan = math2.NAN |
| j = 1j |
|
|
| |
| @classmethod |
| def _wrap_specfun(cls, name, f, wrap): |
| if wrap: |
| def f_wrapped(ctx, *args, **kwargs): |
| convert = ctx.convert |
| args = [convert(a) for a in args] |
| return f(ctx, *args, **kwargs) |
| else: |
| f_wrapped = f |
| f_wrapped.__doc__ = function_docs.__dict__.get(name, f.__doc__) |
| setattr(cls, name, f_wrapped) |
|
|
| def bernoulli(ctx, n): |
| cache = ctx._bernoulli_cache |
| if n in cache: |
| return cache[n] |
| cache[n] = to_float(mpf_bernoulli(n, 53, 'n'), strict=True) |
| return cache[n] |
|
|
| pi = math2.pi |
| e = math2.e |
| euler = math2.euler |
| sqrt2 = 1.4142135623730950488 |
| sqrt5 = 2.2360679774997896964 |
| phi = 1.6180339887498948482 |
| ln2 = 0.69314718055994530942 |
| ln10 = 2.302585092994045684 |
| euler = 0.57721566490153286061 |
| catalan = 0.91596559417721901505 |
| khinchin = 2.6854520010653064453 |
| apery = 1.2020569031595942854 |
| glaisher = 1.2824271291006226369 |
|
|
| absmin = absmax = abs |
|
|
| def is_special(ctx, x): |
| return x - x != 0.0 |
|
|
| def isnan(ctx, x): |
| return x != x |
|
|
| def isinf(ctx, x): |
| return abs(x) == math2.INF |
|
|
| def isnormal(ctx, x): |
| if x: |
| return x - x == 0.0 |
| return False |
|
|
| def isnpint(ctx, x): |
| if type(x) is complex: |
| if x.imag: |
| return False |
| x = x.real |
| return x <= 0.0 and round(x) == x |
|
|
| mpf = float |
| mpc = complex |
|
|
| def convert(ctx, x): |
| try: |
| return float(x) |
| except: |
| return complex(x) |
|
|
| power = staticmethod(math2.pow) |
| sqrt = staticmethod(math2.sqrt) |
| exp = staticmethod(math2.exp) |
| ln = log = staticmethod(math2.log) |
| cos = staticmethod(math2.cos) |
| sin = staticmethod(math2.sin) |
| tan = staticmethod(math2.tan) |
| cos_sin = staticmethod(math2.cos_sin) |
| acos = staticmethod(math2.acos) |
| asin = staticmethod(math2.asin) |
| atan = staticmethod(math2.atan) |
| cosh = staticmethod(math2.cosh) |
| sinh = staticmethod(math2.sinh) |
| tanh = staticmethod(math2.tanh) |
| gamma = staticmethod(math2.gamma) |
| rgamma = staticmethod(math2.rgamma) |
| fac = factorial = staticmethod(math2.factorial) |
| floor = staticmethod(math2.floor) |
| ceil = staticmethod(math2.ceil) |
| cospi = staticmethod(math2.cospi) |
| sinpi = staticmethod(math2.sinpi) |
| cbrt = staticmethod(math2.cbrt) |
| _nthroot = staticmethod(math2.nthroot) |
| _ei = staticmethod(math2.ei) |
| _e1 = staticmethod(math2.e1) |
| _zeta = _zeta_int = staticmethod(math2.zeta) |
|
|
| |
| def arg(ctx, z): |
| z = complex(z) |
| return math.atan2(z.imag, z.real) |
|
|
| def expj(ctx, x): |
| return ctx.exp(ctx.j*x) |
|
|
| def expjpi(ctx, x): |
| return ctx.exp(ctx.j*ctx.pi*x) |
|
|
| ldexp = math.ldexp |
| frexp = math.frexp |
|
|
| def mag(ctx, z): |
| if z: |
| return ctx.frexp(abs(z))[1] |
| return ctx.ninf |
|
|
| def isint(ctx, z): |
| if hasattr(z, "imag"): |
| if z.imag: |
| return False |
| z = z.real |
| try: |
| return z == int(z) |
| except: |
| return False |
|
|
| def nint_distance(ctx, z): |
| if hasattr(z, "imag"): |
| n = round(z.real) |
| else: |
| n = round(z) |
| if n == z: |
| return n, ctx.ninf |
| return n, ctx.mag(abs(z-n)) |
|
|
| def _convert_param(ctx, z): |
| if type(z) is tuple: |
| p, q = z |
| return ctx.mpf(p) / q, 'R' |
| if hasattr(z, "imag"): |
| intz = int(z.real) |
| else: |
| intz = int(z) |
| if z == intz: |
| return intz, 'Z' |
| return z, 'R' |
|
|
| def _is_real_type(ctx, z): |
| return isinstance(z, float) or isinstance(z, int_types) |
|
|
| def _is_complex_type(ctx, z): |
| return isinstance(z, complex) |
|
|
| def hypsum(ctx, p, q, types, coeffs, z, maxterms=6000, **kwargs): |
| coeffs = list(coeffs) |
| num = range(p) |
| den = range(p,p+q) |
| tol = ctx.eps |
| s = t = 1.0 |
| k = 0 |
| while 1: |
| for i in num: t *= (coeffs[i]+k) |
| for i in den: t /= (coeffs[i]+k) |
| k += 1; t /= k; t *= z; s += t |
| if abs(t) < tol: |
| return s |
| if k > maxterms: |
| raise ctx.NoConvergence |
|
|
| def atan2(ctx, x, y): |
| return math.atan2(x, y) |
|
|
| def psi(ctx, m, z): |
| m = int(m) |
| if m == 0: |
| return ctx.digamma(z) |
| return (-1)**(m+1) * ctx.fac(m) * ctx.zeta(m+1, z) |
|
|
| digamma = staticmethod(math2.digamma) |
|
|
| def harmonic(ctx, x): |
| x = ctx.convert(x) |
| if x == 0 or x == 1: |
| return x |
| return ctx.digamma(x+1) + ctx.euler |
|
|
| nstr = str |
|
|
| def to_fixed(ctx, x, prec): |
| return int(math.ldexp(x, prec)) |
|
|
| def rand(ctx): |
| import random |
| return random.random() |
|
|
| _erf = staticmethod(math2.erf) |
| _erfc = staticmethod(math2.erfc) |
|
|
| def sum_accurately(ctx, terms, check_step=1): |
| s = ctx.zero |
| k = 0 |
| for term in terms(): |
| s += term |
| if (not k % check_step) and term: |
| if abs(term) <= 1e-18*abs(s): |
| break |
| k += 1 |
| return s |
|
|