def test_vector_evalf(): a, b = symbols('a b') v = pi * A.x assert v.evalf(2) == Float('3.1416', 2) * A.x v = pi * A.x + 5 * a * A.y - b * A.z assert v.evalf(3) == Float('3.1416', 3) * A.x + Float('5', 3) * a * A.y - b * A.z assert v.evalf(5, subs={a: 1.234, b:5.8973}) == Float('3.1415926536', 5) * A.x + Float('6.17', 5) * A.y - Float('5.8973', 5) * A.z
def test_systematic_basic(): def s(sympy_object, numpy_array): _ = [sympy_object + numpy_array, numpy_array + sympy_object, sympy_object - numpy_array, numpy_array - sympy_object, sympy_object * numpy_array, numpy_array * sympy_object, sympy_object / numpy_array, numpy_array / sympy_object, sympy_object ** numpy_array, numpy_array ** sympy_object] x = Symbol("x") y = Symbol("y") sympy_objs = [ Rational(2, 3), Float("1.3"), x, y, pow(x, y)*y, Integer(5), Float(5.5), ] numpy_objs = [ array([1]), array([3, 8, -1]), array([x, x**2, Rational(5)]), array([x/y*sin(y), 5, Rational(5)]), ] for x in sympy_objs: for y in numpy_objs: s(x, y)
def test_issue_3728(): assert (Rational(1, 2)*array([2*x, 0]) == array([x, 0])).all() assert (Rational(1, 2) + array( [2*x, 0]) == array([2*x + Rational(1, 2), Rational(1, 2)])).all() assert (Float("0.5")*array([2*x, 0]) == array([Float("1.0")*x, 0])).all() assert (Float("0.5") + array( [2*x, 0]) == array([2*x + Float("0.5"), Float("0.5")])).all()
def test_dyadic_evalf(): N = ReferenceFrame('N') a = pi * (N.x | N.x) assert a.evalf(3) == Float('3.1416', 3) * (N.x | N.x) s = symbols('s') a = 5 * s * pi* (N.x | N.x) assert a.evalf(2) == Float('5', 2) * Float('3.1416', 2) * s * (N.x | N.x) assert a.evalf(9, subs={s: 5.124}) == Float('80.48760378', 9) * (N.x | N.x)
def test_RootSum_evalf(): rs = RootSum(x**2 + 1, exp) assert rs.evalf(n=20, chop=True).epsilon_eq(Float("1.0806046117362794348")) assert rs.evalf(n=15, chop=True).epsilon_eq(Float("1.08060461173628")) rs = RootSum(x**2 + a, exp, x) assert rs.evalf() == rs
def test_Number(): assert precedence(Integer(0)) == PRECEDENCE["Atom"] assert precedence(Integer(1)) == PRECEDENCE["Atom"] assert precedence(Integer(-1)) == PRECEDENCE["Add"] assert precedence(Integer(10)) == PRECEDENCE["Atom"] assert precedence(Rational(5, 2)) == PRECEDENCE["Mul"] assert precedence(Rational(-5, 2)) == PRECEDENCE["Add"] assert precedence(Float(5)) == PRECEDENCE["Atom"] assert precedence(Float(-5)) == PRECEDENCE["Add"]
def test_Type__cast_check__complex_floating_point(): val9_11 = 123.456789049 + 0.123456789049j raises(ValueError, lambda: c64.cast_check(.12345678949 + .12345678949j)) assert abs(val9_11 - c64.cast_check(val9_11) - 4.9e-8) < 1e-8 dcm21 = Float('0.123456789012345670499') + 1e-20j # 21 decimals assert abs(dcm21 - c128.cast_check(dcm21) - 4.99e-19) < 1e-19 v19 = Float('0.1234567890123456749') + 1j * Float('0.1234567890123456749') raises(ValueError, lambda: c128.cast_check(v19))
def test_purestr(): assert purestr(Symbol('x')) == "Symbol('x')" assert purestr(Basic(S(1), S(2))) == "Basic(Integer(1), Integer(2))" assert purestr(Float(2)) == "Float('2.0', precision=53)" assert purestr(Symbol('x'), with_args=True) == ("Symbol('x')", ()) assert purestr(Basic(S(1), S(2)), with_args=True) == \ ('Basic(Integer(1), Integer(2))', ('Integer(1)', 'Integer(2)')) assert purestr(Float(2), with_args=True) == \ ("Float('2.0', precision=53)", ())
def test_RR_Float(): f1 = Float("1.01") f2 = Float("1.0000000000000000000001") assert f1._prec == 53 assert f2._prec == 80 assert RR(f1)-1 > 1e-50 assert RR(f2)-1 < 1e-50 # RR's precision is lower than f2's RR2 = RealField(prec=f2._prec) assert RR2(f1)-1 > 1e-50 assert RR2(f2)-1 > 1e-50 # RR's precision is equal to f2's
def test_function_comparable(): assert sin(x).is_comparable is False assert cos(x).is_comparable is False assert sin(Float('0.1')).is_comparable is True assert cos(Float('0.1')).is_comparable is True assert sin(E).is_comparable is True assert cos(E).is_comparable is True assert sin(Rational(1, 3)).is_comparable is True assert cos(Rational(1, 3)).is_comparable is True
def test_rf_ff_eval_hiprec(): maple = Float('6.9109401292234329956525265438452') us = ff(18, Rational(2, 3)).evalf(32) assert abs(us - maple) / us < 1e-31 maple = Float('6.8261540131125511557924466355367') us = rf(18, Rational(2, 3)).evalf(32) assert abs(us - maple) / us < 1e-31 maple = Float('34.007346127440197150854651814225') us = rf(Float('4.4', 32), Float('2.2', 32)) assert abs(us - maple) / us < 1e-31
def test_issue_16759(): d = sympify({.5: 1}) assert S.Half not in d assert Float(.5) in d assert d[.5] is S.One d = sympify(OrderedDict({.5: 1})) assert S.Half not in d assert Float(.5) in d assert d[.5] is S.One d = sympify(defaultdict(int, {.5: 1})) assert S.Half not in d assert Float(.5) in d assert d[.5] is S.One
def _mpc_(self): """ Convert self to an mpmath mpc if possible """ from sympy.core.numbers import I, Float re_part, rest = self.as_coeff_Add() im_part, imag_unit = rest.as_coeff_Mul() if not imag_unit == I: # ValueError may seem more reasonable but since it's a @property, # we need to use AttributeError to keep from confusing things like # hasattr. raise AttributeError("Cannot convert Add to mpc. Must be of the form Number + Number*I") return (Float(re_part)._mpf_, Float(im_part)._mpf_)
def test_scalar_numpy(): if not np: skip("numpy not installed.") assert represent(Integer(1), format='numpy') == 1 assert represent(Float(1.0), format='numpy') == 1.0 assert represent(1.0 + I, format='numpy') == 1.0 + 1.0j
def Ar(element: Any) -> Float: """Retrieve the relative atomic mass of the element. :param element: Any object that provides a __str__ or __repr__ method that gives a string of the symbol of an element. :return: The relative atomic mass of the element (in amu). :raise LookupError: Raised when the element symbol can not be found in data. >>> Ar('H') 1.01 >>> Ar(sympy.Symbol('H')) 1.01 >>> class Foo: ... def __repr__(self): ... return 'H' >>> Ar(Foo()) 1.01 >>> Ar('Ha') # not an element Traceback (most recent call last): ... LookupError: unknown element symbol 'Ha' """ symbol = str(element) if symbol in ATOMIC_MASSES: return Float(ATOMIC_MASSES[symbol], 3) raise LookupError(f"unknown element symbol '{symbol}'")
def test_rf_lambdify_mpmath(): from sympy.utilities.lambdify import lambdify x, y = symbols('x,y') f = lambdify((x, y), rf(x, y), 'mpmath') maple = Float('34.007346127440197') us = f(4.4, 2.2) assert abs(us - maple) / us < 1e-15
def test_sympy_lambda(): mpmath.mp.dps = 50 sin02 = mpmath.mpf("0.19866933079506121545941262711838975037020672954020") f = lambdify(x, sin(x), "sympy") assert f(x) == sin(x) prec = 1e-15 assert -prec < f(Rational(1, 5)).evalf() - Float(str(sin02)) < prec
def test__sympify(): x = Symbol('x') f = Function('f') # positive _sympify assert _sympify(x) is x assert _sympify(1) == Integer(1) assert _sympify(0.5) == Float("0.5") assert _sympify(1 + 1j) == 1.0 + I * 1.0 # Function f is not Basic and can't sympify to Basic. We allow it to pass # with sympify but not with _sympify. # https://github.com/sympy/sympy/issues/20124 assert sympify(f) is f raises(SympifyError, lambda: _sympify(f)) class A: def _sympy_(self): return Integer(5) a = A() assert _sympify(a) == Integer(5) # negative _sympify raises(SympifyError, lambda: _sympify('1')) raises(SympifyError, lambda: _sympify([1, 2, 3]))
def dotest(s): x = Symbol("x") y = Symbol("y") l = [Rational(2), Float("1.3"), x, y, pow(x, y) * y, 5, 5.5] for x in l: for y in l: s(x, y) return True
def test_hbar(): assert hbar.is_commutative is True assert hbar.is_real is True assert hbar.is_positive is True assert hbar.is_negative is False assert hbar.is_irrational is True assert hbar.evalf() == Float(1.05457162e-34)
def test_precision(): f1 = Float("1.01") f2 = Float("1.0000000000000000000001") for u in [ 1, 1e-2, 1e-6, 1e-13, 1e-14, 1e-16, 1e-20, 1e-100, 1e-300, f1, f2 ]: result = construct_domain([u]) v = float(result[1][0]) assert abs(u - v) / u < 1e-14 # Test relative accuracy result = construct_domain([f1]) y = result[1][0] assert y - 1 > 1e-50 result = construct_domain([f2]) y = result[1][0] assert y - 1 > 1e-50
def _pi_coeff(arg, cycles=1): """ When arg is a Number times pi (e.g. 3*pi/2) then return the Number normalized to be in the range [0, 2], else None. When an even multiple of pi is encountered, if it is multiplying something with known parity then the multiple is returned as 0 otherwise as 2. Examples: >>> from sympy.functions.elementary.trigonometric import _pi_coeff as coeff >>> from sympy import pi >>> from sympy.abc import x, y >>> coeff(3*x*pi) 3*x >>> coeff(11*pi/7) 11/7 >>> coeff(-11*pi/7) 3/7 >>> coeff(4*pi) 0 >>> coeff(5*pi) 1 >>> coeff(5.0*pi) 1 >>> coeff(5.5*pi) 3/2 >>> coeff(2 + pi) """ arg = sympify(arg) if arg is S.Pi: return S.One elif not arg: return S.Zero elif arg.is_Mul: cx = arg.coeff(S.Pi) if cx: c, x = cx.as_coeff_Mul() # pi is not included as coeff if c.is_Float: # recast exact binary fractions to Rationals m = int(c * 2) if Float(float(m) / 2) == c: c = Rational(m, 2) if x is not S.One or not (c.is_Rational and c.q != 1): if x.is_integer: c2 = c % 2 if c2 == 1: return x elif not c2: if x.is_even is not None: # known parity return S.Zero return 2 * x else: return c2 * x return cx else: return Rational(c.p % (2 * c.q), c.q)
def test_sympify_numpy(): if not numpy: skip('numpy not installed. Abort numpy tests.') np = numpy def equal(x, y): return x == y and type(x) == type(y) assert sympify(np.bool_(1)) is S(True) try: assert equal(sympify(np.int_(1234567891234567891)), S(1234567891234567891)) assert equal(sympify(np.intp(1234567891234567891)), S(1234567891234567891)) except OverflowError: # May fail on 32-bit systems: Python int too large to convert to C long pass assert equal(sympify(np.intc(1234567891)), S(1234567891)) assert equal(sympify(np.int8(-123)), S(-123)) assert equal(sympify(np.int16(-12345)), S(-12345)) assert equal(sympify(np.int32(-1234567891)), S(-1234567891)) assert equal(sympify(np.int64(-1234567891234567891)), S(-1234567891234567891)) assert equal(sympify(np.uint8(123)), S(123)) assert equal(sympify(np.uint16(12345)), S(12345)) assert equal(sympify(np.uint32(1234567891)), S(1234567891)) assert equal(sympify(np.uint64(1234567891234567891)), S(1234567891234567891)) assert equal(sympify(np.float32(1.123456)), Float(1.123456, precision=24)) assert equal(sympify(np.float64(1.1234567891234)), Float(1.1234567891234, precision=53)) assert equal(sympify(np.longdouble(1.123456789)), Float(1.123456789, precision=80)) assert equal(sympify(np.complex64(1 + 2j)), S(1.0 + 2.0 * I)) assert equal(sympify(np.complex128(1 + 2j)), S(1.0 + 2.0 * I)) assert equal(sympify(np.longcomplex(1 + 2j)), S(1.0 + 2.0 * I)) #float96 does not exist on all platforms if hasattr(np, 'float96'): assert equal(sympify(np.float96(1.123456789)), Float(1.123456789, precision=80)) #float128 does not exist on all platforms if hasattr(np, 'float128'): assert equal(sympify(np.float128(1.123456789123)), Float(1.123456789123, precision=80))
def test_issue_8245(): a = S("6506833320952669167898688709329/5070602400912917605986812821504") assert rel_check(a, a.n(10)) assert rel_check(a, a.n(20)) assert rel_check(a, a.n()) # prec of 30 is enough to fully capture a as mpf assert Float(a, 30) == Float(str(a.p), '') / Float(str(a.q), '') for i in range(31): r = Rational(Float(a, i)) f = Float(r) assert (f < a) == (Rational(f) < a) # test sign handling assert (-f < -a) == (Rational(-f) < -a) # test equivalence handling isa = Float(a.p, '') / Float(a.q, '') assert isa <= a assert not isa < a assert isa >= a assert not isa > a assert isa > 0 a = sqrt(2) r = Rational(str(a.n(30))) assert rel_check(a, r) a = sqrt(2) r = Rational(str(a.n(29))) assert rel_check(a, r) assert Eq(log(cos(2)**2 + sin(2)**2), 0) is S.true
def test_issue_2877(): f = Float(2.0) assert (x + f).subs({f: 2}) == x + 2 def r(a, b, c): return factor(a * x**2 + b * x + c) e = r(5.0 / 6, 10, 5) assert nsimplify(e) == 5 * x**2 / 6 + 10 * x + 5
def test_Type__cast_check__integers(): # Rounding raises(ValueError, lambda: integer.cast_check(3.5)) assert integer.cast_check('3') == 3 assert integer.cast_check(Float('3.0000000000000000000')) == 3 assert integer.cast_check( Float('3.0000000000000000001')) == 3 # unintuitive maybe? # Range assert int8.cast_check(127.0) == 127 raises(ValueError, lambda: int8.cast_check(128)) assert int8.cast_check(-128) == -128 raises(ValueError, lambda: int8.cast_check(-129)) assert uint8.cast_check(0) == 0 assert uint8.cast_check(128) == 128 raises(ValueError, lambda: uint8.cast_check(256.0)) raises(ValueError, lambda: uint8.cast_check(-1))
def fit_traj_segment(p_start, p_end, v_start, v_end, p_max, v_max, a_max, j_max, independent_variable=Symbol('t')): ''' This function selects a motion profile for a general trajectory segment with a given start/end velocities/positions considering the start and end accelerations/jerks are zeros ''' # Step_1. calculate jerk_sign_and_duration segment_jerks_and_durations = calculate_jerk_sign_and_duration( p_start, p_end, v_start, v_end, p_max, v_max, a_max, j_max, independent_variable=Symbol('t')) # Step_2: generate pos, vel, acc, jrk using the calculated "segment_jerks_and_durations" p0 = p_start v0 = v_start a0 = 0.0 times = [0.0] jerk_functions = [] acceleration_functions = [] velocity_functions = [] position_functions = [] # Integrate jerk starting from the start of the trajectory and going all the way through the end. for j0, T in segment_jerks_and_durations: times.append(times[-1] + T) j = Float(j0) a = integrate(j, independent_variable) + a0 v = integrate(a, independent_variable) + v0 p = integrate(v, independent_variable) + p0 jerk_functions.append(j) acceleration_functions.append(a) velocity_functions.append(v) position_functions.append(p) a0 = a.subs({independent_variable: T}) v0 = v.subs({independent_variable: T}) p0 = p.subs({independent_variable: T}) position = PiecewiseFunction(times, position_functions, independent_variable) velocity = PiecewiseFunction(times, velocity_functions, independent_variable) acceleration = PiecewiseFunction(times, acceleration_functions, independent_variable) jerk = PiecewiseFunction(times, jerk_functions, independent_variable) return position, velocity, acceleration, jerk
def test_scalar_scipy_sparse(): if not np: skip("numpy not installed.") if not scipy: skip("scipy not installed.") assert represent(Integer(1), format='scipy.sparse') == 1 assert represent(Float(1.0), format='scipy.sparse') == 1.0 assert represent(1.0 + I, format='scipy.sparse') == 1.0 + 1.0j
def test_lambertw(): k = Symbol('k') assert LambertW(x, 0) == LambertW(x) assert LambertW(x, 0, evaluate=False) != LambertW(x) assert LambertW(0) == 0 assert LambertW(E) == 1 assert LambertW(-1 / E) == -1 assert LambertW(-log(2) / 2) == -log(2) assert LambertW(oo) is oo assert LambertW(0, 1) is -oo assert LambertW(0, 42) is -oo assert LambertW(-pi / 2, -1) == -I * pi / 2 assert LambertW(-1 / E, -1) == -1 assert LambertW(-2 * exp(-2), -1) == -2 assert LambertW(2 * log(2)) == log(2) assert LambertW(-pi / 2) == I * pi / 2 assert LambertW(exp(1 + E)) == E assert LambertW( x**2).diff(x) == 2 * LambertW(x**2) / x / (1 + LambertW(x**2)) assert LambertW(x, k).diff(x) == LambertW(x, k) / x / (1 + LambertW(x, k)) assert LambertW(sqrt(2)).evalf(30).epsilon_eq( Float("0.701338383413663009202120278965", 30), 1e-29) assert re(LambertW(2, -1)).evalf().epsilon_eq(Float("-0.834310366631110")) assert LambertW(-1).is_real is False # issue 5215 assert LambertW(2, evaluate=False).is_real p = Symbol('p', positive=True) assert LambertW(p, evaluate=False).is_real assert LambertW(p - 1, evaluate=False).is_real is None assert LambertW(-p - 2 / S.Exp1, evaluate=False).is_real is False assert LambertW(S.Half, -1, evaluate=False).is_real is False assert LambertW(Rational(-1, 10), -1, evaluate=False).is_real assert LambertW(-10, -1, evaluate=False).is_real is False assert LambertW(-2, 2, evaluate=False).is_real is False assert LambertW(0, evaluate=False).is_algebraic na = Symbol('na', nonzero=True, algebraic=True) assert LambertW(na).is_algebraic is False assert LambertW(p).is_zero is False n = Symbol('n', negative=True) assert LambertW(n).is_zero is False
def test_core_numbers(): for c in (Catalan, Catalan(), ComplexInfinity, ComplexInfinity(), EulerGamma, EulerGamma(), Exp1, Exp1(), GoldenRatio, GoldenRatio(), Half, Half(), ImaginaryUnit, ImaginaryUnit(), Infinity, Infinity(), Integer, Integer(2), NaN, NaN(), NegativeInfinity, NegativeInfinity(), NegativeOne, NegativeOne(), Number, Number(15), NumberSymbol, NumberSymbol(), One, One(), Pi, Pi(), Rational, Rational(1, 2), Float, Float("1.2"), Zero, Zero()): check(c)
def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False): """ Evaluate the given formula to an accuracy of n digits. Optional keyword arguments: subs=<dict> Substitute numerical values for symbols, e.g. subs={x:3, y:1+pi}. The substitutions must be given as a dictionary. maxn=<integer> Allow a maximum temporary working precision of maxn digits (default=100) chop=<bool> Replace tiny real or imaginary parts in subresults by exact zeros (default=False) strict=<bool> Raise PrecisionExhausted if any subresult fails to evaluate to full accuracy, given the available maxprec (default=False) quad=<str> Choose algorithm for numerical quadrature. By default, tanh-sinh quadrature is used. For oscillatory integrals on an infinite interval, try quad='osc'. verbose=<bool> Print debug information (default=False) """ from sympy import Float, Number n = n if n is not None else 15 if subs and is_sequence(subs): raise TypeError('subs must be given as a dictionary') # for sake of sage that doesn't like evalf(1) if n == 1 and isinstance(self, Number): from sympy.core.expr import _mag rv = self.evalf(2, subs, maxn, chop, strict, quad, verbose) m = _mag(rv) rv = rv.round(1 - m) return rv if not evalf_table: _create_evalf_table() prec = dps_to_prec(n) options = {'maxprec': max(prec, int(maxn*LG10)), 'chop': chop, 'strict': strict, 'verbose': verbose} if subs is not None: options['subs'] = subs if quad is not None: options['quad'] = quad try: result = evalf(self, prec + 4, options) except NotImplementedError: # Fall back to the ordinary evalf v = self._eval_evalf(prec) if v is None: return self try: # If the result is numerical, normalize it result = evalf(v, prec, options) except NotImplementedError: # Probably contains symbols or unknown functions return v re, im, re_acc, im_acc = result if re: p = max(min(prec, re_acc), 1) re = Float._new(re, p) else: re = S.Zero if im: p = max(min(prec, im_acc), 1) im = Float._new(im, p) return re + im*S.ImaginaryUnit else: return re
def add_terms(terms, prec, target_prec): """ Helper for evalf_add. Adds a list of (mpfval, accuracy) terms. Returns ------- - None, None if there are no non-zero terms; - terms[0] if there is only 1 term; - scaled_zero if the sum of the terms produces a zero by cancellation e.g. mpfs representing 1 and -1 would produce a scaled zero which need special handling since they are not actually zero and they are purposely malformed to ensure that they can't be used in anything but accuracy calculations; - a tuple that is scaled to target_prec that corresponds to the sum of the terms. The returned mpf tuple will be normalized to target_prec; the input prec is used to define the working precision. XXX explain why this is needed and why one can't just loop using mpf_add """ terms = [t for t in terms if not iszero(t)] if not terms: return None, None elif len(terms) == 1: return terms[0] # see if any argument is NaN or oo and thus warrants a special return special = [] from sympy.core.numbers import Float for t in terms: arg = Float._new(t[0], 1) if arg is S.NaN or arg.is_infinite: special.append(arg) if special: from sympy.core.add import Add rv = evalf(Add(*special), prec + 4, {}) return rv[0], rv[2] working_prec = 2*prec sum_man, sum_exp, absolute_error = 0, 0, MINUS_INF for x, accuracy in terms: sign, man, exp, bc = x if sign: man = -man absolute_error = max(absolute_error, bc + exp - accuracy) delta = exp - sum_exp if exp >= sum_exp: # x much larger than existing sum? # first: quick test if ((delta > working_prec) and ((not sum_man) or delta - bitcount(abs(sum_man)) > working_prec)): sum_man = man sum_exp = exp else: sum_man += (man << delta) else: delta = -delta # x much smaller than existing sum? if delta - bc > working_prec: if not sum_man: sum_man, sum_exp = man, exp else: sum_man = (sum_man << delta) + man sum_exp = exp if not sum_man: return scaled_zero(absolute_error) if sum_man < 0: sum_sign = 1 sum_man = -sum_man else: sum_sign = 0 sum_bc = bitcount(sum_man) sum_accuracy = sum_exp + sum_bc - absolute_error r = normalize(sum_sign, sum_man, sum_exp, sum_bc, target_prec, rnd), sum_accuracy return r
def evalf_mul(v, prec, options): res = pure_complex(v) if res: # the only pure complex that is a mul is h*I _, h = res im, _, im_acc, _ = evalf(h, prec, options) return None, im, None, im_acc args = list(v.args) # see if any argument is NaN or oo and thus warrants a special return special = [] from sympy.core.numbers import Float for arg in args: arg = evalf(arg, prec, options) if arg[0] is None: continue arg = Float._new(arg[0], 1) if arg is S.NaN or arg.is_infinite: special.append(arg) if special: from sympy.core.mul import Mul special = Mul(*special) return evalf(special, prec + 4, {}) # With guard digits, multiplication in the real case does not destroy # accuracy. This is also true in the complex case when considering the # total accuracy; however accuracy for the real or imaginary parts # separately may be lower. acc = prec # XXX: big overestimate working_prec = prec + len(args) + 5 # Empty product is 1 start = man, exp, bc = MPZ(1), 0, 1 # First, we multiply all pure real or pure imaginary numbers. # direction tells us that the result should be multiplied by # I**direction; all other numbers get put into complex_factors # to be multiplied out after the first phase. last = len(args) direction = 0 args.append(S.One) complex_factors = [] for i, arg in enumerate(args): if i != last and pure_complex(arg): args[-1] = (args[-1]*arg).expand() continue elif i == last and arg is S.One: continue re, im, re_acc, im_acc = evalf(arg, working_prec, options) if re and im: complex_factors.append((re, im, re_acc, im_acc)) continue elif re: (s, m, e, b), w_acc = re, re_acc elif im: (s, m, e, b), w_acc = im, im_acc direction += 1 else: return None, None, None, None direction += 2*s man *= m exp += e bc += b if bc > 3*working_prec: man >>= working_prec exp += working_prec acc = min(acc, w_acc) sign = (direction & 2) >> 1 if not complex_factors: v = normalize(sign, man, exp, bitcount(man), prec, rnd) # multiply by i if direction & 1: return None, v, None, acc else: return v, None, acc, None else: # initialize with the first term if (man, exp, bc) != start: # there was a real part; give it an imaginary part re, im = (sign, man, exp, bitcount(man)), (0, MPZ(0), 0, 0) i0 = 0 else: # there is no real part to start (other than the starting 1) wre, wim, wre_acc, wim_acc = complex_factors[0] acc = min(acc, complex_accuracy((wre, wim, wre_acc, wim_acc))) re = wre im = wim i0 = 1 for wre, wim, wre_acc, wim_acc in complex_factors[i0:]: # acc is the overall accuracy of the product; we aren't # computing exact accuracies of the product. acc = min(acc, complex_accuracy((wre, wim, wre_acc, wim_acc))) use_prec = working_prec A = mpf_mul(re, wre, use_prec) B = mpf_mul(mpf_neg(im), wim, use_prec) C = mpf_mul(re, wim, use_prec) D = mpf_mul(im, wre, use_prec) re = mpf_add(A, B, use_prec) im = mpf_add(C, D, use_prec) if options.get('verbose'): print("MUL: wanted", prec, "accurate bits, got", acc) # multiply by I if direction & 1: re, im = mpf_neg(im), re return re, im, acc, acc