def mpf_asin(x, prec, rnd=round_fast): sign, man, exp, bc = x if bc+exp > 0 and x not in (fone, fnone): raise ComplexResult("asin(x) is real only for -1 <= x <= 1") flag_nr = True if prec < 1000 or exp+bc < -13: flag_nr = False else: ebc = exp + bc if ebc < -13: flag_nr = False elif ebc < -3: if prec < 3000: flag_nr = False if not flag_nr: # asin(x) = 2*atan(x/(1+sqrt(1-x**2))) wp = prec + 15 a = mpf_mul(x, x) b = mpf_add(fone, mpf_sqrt(mpf_sub(fone, a, wp), wp), wp) c = mpf_div(x, b, wp) return mpf_shift(mpf_atan(c, prec, rnd), 1) # use Newton's method extra = 10 extra_p = 10 prec2 = prec + extra r = math.asin(to_float(x)) r = from_float(r, 50, rnd) for p in giant_steps(50, prec2): wp = p + extra_p c, s = cos_sin(r, wp, rnd) tmp = mpf_sub(x, s, wp, rnd) tmp = mpf_div(tmp, c, wp, rnd) r = mpf_add(r, tmp, wp, rnd) sign, man, exp, bc = r return normalize(sign, man, exp, bc, prec, rnd)
def try_convert_mpf_value(x, prec, rounding): if isinstance(x, float): return from_float(x) if hasattr(x, '_mpf_'): return x._mpf_ if hasattr(x, '_mpmath_'): t = mpmathify(x._mpmath_(prec, rounding)) if isinstance(t, mpf): return t._mpf_ return NotImplemented
def try_convert_mpf_value(x, prec, rounding): if isinstance(x, float): return from_float(x) if hasattr(x, '_mpf_'): return x._mpf_ if hasattr(x, '_mpmath_'): t = convert_lossless(x._mpmath_(prec, rounding)) if isinstance(t, mpf): return t._mpf_ return NotImplemented
def mpf_convert_rhs(x): if isinstance(x, int_types): return from_int(x) if isinstance(x, float): return from_float(x) if isinstance(x, complex_types): return mpc(x) if hasattr(x, '_mpf_'): return x._mpf_ if hasattr(x, '_mpmath_'): t = mpmathify(x._mpmath_(*prec_rounding)) if isinstance(t, mpf): return t._mpf_ return t return NotImplemented
def mpf_convert_arg(x, prec, rounding): if isinstance(x, int_types): return from_int(x) if isinstance(x, float): return from_float(x) if isinstance(x, basestring): return from_str(x, prec, rounding) if isinstance(x, constant): return x.func(prec, rounding) if hasattr(x, '_mpf_'): return x._mpf_ if hasattr(x, '_mpmath_'): t = mpmathify(x._mpmath_(prec, rounding)) if isinstance(t, mpf): return t._mpf_ raise TypeError("cannot create mpf from " + repr(x))
def mpf_convert_rhs(x): if isinstance(x, int_types): return from_int(x) if isinstance(x, float): return from_float(x) if isinstance(x, complex_types): return mpc(x) if hasattr(x, '_mpf_'): return x._mpf_ if hasattr(x, '_mpmath_'): t = convert_lossless(x._mpmath_(*prec_rounding)) if isinstance(t, mpf): return t._mpf_ return t return NotImplemented
def mpf_convert_arg(x, prec, rounding): if isinstance(x, int_types): return from_int(x) if isinstance(x, float): return from_float(x) if isinstance(x, basestring): return from_str(x, prec, rounding) if isinstance(x, constant): return x.func(prec, rounding) if hasattr(x, '_mpf_'): return x._mpf_ if hasattr(x, '_mpmath_'): t = convert_lossless(x._mpmath_(prec, rounding)) if isinstance(t, mpf): return t._mpf_ raise TypeError("cannot create mpf from " + repr(x))
def convert_lossless(x, strings=True): """Attempt to convert x to an mpf or mpc losslessly. If x is an mpf or mpc, return it unchanged. If x is an int, create an mpf with sufficient precision to represent it exactly. If x is a str, just convert it to an mpf with the current working precision (perhaps this should be done differently...)""" if isinstance(x, mpnumeric): return x if isinstance(x, int_types): return make_mpf(from_int(x)) if isinstance(x, float): return make_mpf(from_float(x)) if isinstance(x, complex): return mpc(x) if strings and isinstance(x, basestring): return make_mpf(from_str(x, *prec_rounding)) if hasattr(x, '_mpf_'): return make_mpf(x._mpf_) if hasattr(x, '_mpc_'): return make_mpc(x._mpc_) if hasattr(x, '_mpmath_'): return convert_lossless(x._mpmath_(*prec_rounding)) raise TypeError("cannot create mpf from " + repr(x))
def mpmathify(x, strings=True): """ Converts *x* to an ``mpf`` or ``mpc``. If *x* is of type ``mpf``, ``mpc``, ``int``, ``float``, ``complex``, the conversion will be performed losslessly. If *x* is a string, the result will be rounded to the present working precision. Strings representing fractions or complex numbers are permitted. >>> from sympy.mpmath import * >>> mp.dps = 15 >>> mpmathify(3.5) mpf('3.5') >>> mpmathify('2.1') mpf('2.1000000000000001') >>> mpmathify('3/4') mpf('0.75') >>> mpmathify('2+3j') mpc(real='2.0', imag='3.0') """ if isinstance(x, mpnumeric): return x if isinstance(x, int_types): return make_mpf(from_int(x)) if isinstance(x, float): return make_mpf(from_float(x)) if isinstance(x, complex): return mpc(x) if strings and isinstance(x, basestring): try: return make_mpf(from_str(x, *prec_rounding)) except Exception, e: if '/' in x: fract = x.split('/') assert len(fract) == 2 return mpmathify(fract[0]) / mpmathify(fract[1]) if 'j' in x.lower(): x = x.lower().replace(' ', '') match = get_complex.match(x) re = match.group('re') if not re: re = 0 im = match.group('im').rstrip('j') return mpc(mpmathify(re), mpmathify(im)) raise e
wp = prec + 15 x = mpf_add(fone, b, wp), mpf_neg(a) y = mpf_sub(fone, b, wp), a l1 = mpc_log(x, wp) l2 = mpc_log(y, wp) a, b = mpc_sub(l1, l2, prec, rnd) # (I/2) * (a+b*I) = (-b/2 + a/2*I) v = mpf_neg(mpf_shift(b, -1)), mpf_shift(a, -1) # Subtraction at infinity gives correct real part but # wrong imaginary part (should be zero) if v[1] == fnan and mpc_is_inf(z): v = (v[0], fzero) return v beta_crossover = from_float(0.6417) alpha_crossover = from_float(1.5) def acos_asin(z, prec, rnd, n): """ complex acos for n = 0, asin for n = 1 The algorithm is described in T.E. Hull, T.F. Fairgrieve and P.T.P. Tang 'Implementing the Complex Arcsine and Arcosine Functions using Exception Handling', ACM Trans. on Math. Software Vol. 23 (1997), p299 The complex acos and asin can be defined as acos(z) = acos(beta) - I*sign(a)* log(alpha + sqrt(alpha**2 -1)) asin(z) = asin(beta) + I*sign(a)* log(alpha + sqrt(alpha**2 -1)) where z = a + I*b alpha = (1/2)*(r + s); beta = (1/2)*(r - s) = a/alpha
# TODO: avoid loss of accuracy def mpc_atan((a, b), prec, rnd=round_fast): # atan(z) = (I/2)*(log(1-I*z) - log(1+I*z)) # x = 1-I*z = 1 + b - I*a # y = 1+I*z = 1 - b + I*a wp = prec + 15 x = mpf_add(fone, b, wp), mpf_neg(a) y = mpf_sub(fone, b, wp), a l1 = mpc_log(x, wp) l2 = mpc_log(y, wp) a, b = mpc_sub(l1, l2, prec, rnd) # (I/2) * (a+b*I) = (-b/2 + a/2*I) return mpf_neg(mpf_shift(b, -1)), mpf_shift(a, -1) beta_crossover = from_float(0.6417) alpha_crossover = from_float(1.5) def acos_asin(z, prec, rnd, n): """ complex acos for n = 0, asin for n = 1 The algorithm is described in T.E. Hull, T.F. Fairgrieve and P.T.P. Tang 'Implementing the Complex Arcsine and Arcosine Functions using Exception Handling', ACM Trans. on Math. Software Vol. 23 (1997), p299 The complex acos and asin can be defined as acos(z) = acos(beta) - I*sign(a)* log(alpha + sqrt(alpha**2 -1)) asin(z) = asin(beta) + I*sign(a)* log(alpha + sqrt(alpha**2 -1)) where z = a + I*b alpha = (1/2)*(r + s); beta = (1/2)*(r - s) = a/alpha
if n == 1: return mpci_pos(x, prec) if n == 2: return mpci_square(x, prec) wp = prec + 20 result = (mpi_one, mpi_zero) while n: if n & 1: result = mpci_mul(result, x, wp) n -= 1 x = mpci_square(x, wp) n >>= 1 return mpci_pos(result, prec) gamma_min_a = from_float(1.46163214496) gamma_min_b = from_float(1.46163214497) gamma_min = (gamma_min_a, gamma_min_b) gamma_mono_imag_a = from_float(-1.1) gamma_mono_imag_b = from_float(1.1) def mpi_overlap(x, y): a, b = x c, d = y if mpf_lt(d, a): return False if mpf_gt(c, b): return False return True # type = 0 -- gamma
return mpi_one, mpi_zero if n == 1: return mpci_pos(x, prec) if n == 2: return mpci_square(x, prec) wp = prec + 20 result = (mpi_one, mpi_zero) while n: if n & 1: result = mpci_mul(result, x, wp) n -= 1 x = mpci_square(x, wp) n >>= 1 return mpci_pos(result, prec) gamma_min_a = from_float(1.46163214496) gamma_min_b = from_float(1.46163214497) gamma_min = (gamma_min_a, gamma_min_b) gamma_mono_imag_a = from_float(-1.1) gamma_mono_imag_b = from_float(1.1) def mpi_overlap(x, y): a, b = x c, d = y if mpf_lt(d, a): return False if mpf_gt(c, b): return False return True # type = 0 -- gamma # type = 1 -- factorial # type = 2 -- 1/gamma