def modified_round(w, p=0):
    """
    sympy expr.round() function modified so that gives extra digits
    in it representation when p <= 0
    """
    try:
        from mpmath.libmp import prec_to_dps
    except ImportError:
        from sympy.mpmath.libmp import prec_to_dps

    from sympy.core.expr import _mag
    from sympy import Pow, Rational, Integer

    x = w
    if not x.is_number:
        raise TypeError('%s is not a number' % type(x))
    if x in (S.NaN, S.Infinity, S.NegativeInfinity, S.ComplexInfinity):
        return x
    if not x.is_real:
        i, r = x.as_real_imag()
        return i.round(p) + S.ImaginaryUnit*r.round(p)
    if not x:
        return x
    p = int(p)

    precs = [f._prec for f in x.atoms(Float)]
    dps = prec_to_dps(max(precs)) if precs else None

    mag_first_dig = _mag(x)
    allow = digits_needed = mag_first_dig + p
    if p <= 0:
        allow += 1
        digits_needed += 1
    if dps is not None and allow > dps:
        allow = dps
    mag = Pow(10, p)  # magnitude needed to bring digit p to units place
    xwas = x
    x += 1/(2*mag)  # add the half for rounding
    i10 = 10*mag*x.n((dps if dps is not None else digits_needed) + 1)
    if i10.is_negative:
        x = xwas - 1/(2*mag)  # should have gone the other way
        i10 = 10*mag*x.n((dps if dps is not None else digits_needed) + 1)
        rv = -(Integer(-i10)//10)
    else:
        rv = Integer(i10)//10
    q = 1
    if p > 0:
        q = mag
    elif p < 0:
        rv /= mag
    rv = Rational(rv, q)
    if rv.is_Integer:
        # use str or else it won't be a float
        return Float(str(rv), digits_needed)
    else:
        if not allow and rv > w:
            allow += 1
        return Float(rv, allow)
Example #2
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}.

            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)

        """
        # for sake of sage that doesn't like evalf(1)
        if n == 1 and isinstance(self, C.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 = mpf_pos(re, p, rnd)
            re = C.Float._new(re, p)
        else:
            re = S.Zero
        if im:
            p = max(min(prec, im_acc), 1)
            # im = mpf_pos(im, p, rnd)
            im = C.Float._new(im, p)
            return re + im * S.ImaginaryUnit
        else:
            return re
Example #3
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)

        """
        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, C.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 = mpf_pos(re, p, rnd)
            re = C.Float._new(re, p)
        else:
            re = S.Zero
        if im:
            p = max(min(prec, im_acc), 1)
            #im = mpf_pos(im, p, rnd)
            im = C.Float._new(im, p)
            return re + im*S.ImaginaryUnit
        else:
            return re