Beispiel #1
0
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
Beispiel #2
0
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)
Beispiel #3
0
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()
Beispiel #4
0
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"]
Beispiel #7
0
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))
Beispiel #8
0
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)", ())
Beispiel #9
0
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
Beispiel #10
0
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
Beispiel #12
0
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
Beispiel #13
0
    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_)
Beispiel #14
0
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
Beispiel #15
0
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
Beispiel #17
0
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
Beispiel #18
0
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]))
Beispiel #19
0
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
Beispiel #20
0
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)
Beispiel #21
0
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)
Beispiel #23
0
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))
Beispiel #24
0
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
Beispiel #25
0
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
Beispiel #26
0
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))
Beispiel #27
0
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
Beispiel #28
0
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
Beispiel #29
0
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
Beispiel #30
0
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)
Beispiel #31
0
    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
Beispiel #32
0
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
Beispiel #33
0
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