示例#1
0
def log(x, b=None):
    """
    log(x)    -> the natural (base e) logarithm of x
    log(x, b) -> the base b logarithm of x

    """
    # Basic input management
    if b is not None:
        Float._prec += 3
        if b == 2:
            blog = log2_float()
        elif b == 10:
            blog = log10_float()
        else:
            blog = log(b)
        l = log(x) / blog
        Float._prec -= 3
        return l

    if x == 0:
        raise ValueError, "logarithm of 0"

    if isinstance(x, (ComplexFloat, complex)):
        mag = abs(x)
        phase = atan2(x.imag, x.real)
        return ComplexFloat(log(mag), phase)

    if not isinstance(x, Float):
        x = Float(x)

    if x < 0:
        return log(ComplexFloat(x))

    if x == 1:
        return Float((0, 0))

    bc = bitcount(x.man)
    # Estimated precision needed for log(t) + n*log(2)
    prec = Float._prec + int(_clog(1 + abs(bc + x.exp), 2)) + 10

    # Watch out for the case when x is very close to 1
    if -1 < bc + x.exp < 2:
        near_one = abs(x - 1)
        if near_one == 0:
            return Float((0, 0))
        prec += -(near_one.exp) - bitcount(near_one.man)

    # Separate mantissa and exponent, calculate fixed-point
    # approximation and put it all together
    t = _rshift(x.man, bc - prec)
    l = _log_newton(t, prec)
    a = (x.exp + bc) * log2_fixed(prec)
    return Float((l + a, -prec))
示例#2
0
def normalize(man, exp, prec, mode):
    """
    Normalize the binary floating-point number represented by
    man * 2**exp to the specified precision level, rounding
    according to the specified rounding mode if necessary.
    The mantissa is also stripped of trailing zero bits, and
    its bits are counted. The returned value is a tuple
    (man, exp, bc).
    """
    if not man:
        return 0, 0, 0
    bc = bitcount(man)
    if bc > prec:
        man = rshift(man, bc-prec, mode)
        exp += (bc - prec)
        bc = prec
    # Stripping trailing zeros permits faster equality testing
    if not man & 1:
        tr = trailing_zeros(man)
        if tr:
            man >>= tr
            exp += tr
            bc -= tr
    if not man:
        return 0, 0, 0
    return man, exp, bc
示例#3
0
def cos_sin(x):
    """
    cos_sin(x) calculates both the cosine and the sine of x rounded
    to the nearest Float value, and returns the tuple (cos(x), sin(x)).
    """
    if not isinstance(x, Float):
        x = Float(x)
    bits_from_unit = abs(bitcount(x.man) + x.exp)
    prec = Float._prec + bits_from_unit + 15
    xf = make_fixed(x, prec)
    n, rx = _trig_reduce(xf, prec)
    case = n % 4
    one = 1 << prec
    if case == 0:
        s = _sin_series(rx, prec)
        c = _sqrt_fixed(one - ((s * s) >> prec), prec)
    elif case == 1:
        c = -_sin_series(rx, prec)
        s = _sqrt_fixed(one - ((c * c) >> prec), prec)
    elif case == 2:
        s = -_sin_series(rx, prec)
        c = -_sqrt_fixed(one - ((s * s) >> prec), prec)
    elif case == 3:
        c = _sin_series(rx, prec)
        s = -_sqrt_fixed(one - ((c * c) >> prec), prec)
    return Float((c, -prec)), Float((s, -prec))
示例#4
0
def sqrt(x):
    """
    If x is a positive Float, sqrt(x) returns the square root of x as a
    Float, rounded to the current working precision. If x is negative
    or a ComplexFloat, it returns the principal square root of x
    as a ComplexFloat.
    """
    if isinstance(x, (complex, ComplexFloat)):
        return _csqrt(x)
    if not isinstance(x, Float):
        x = Float(x)
    if x == 0:
        return Float(0)
    if x < 0:
        return _csqrt(ComplexFloat(x, 0))
    prec = Float._prec + 4
    # Convert to a fixed-point number with prec bits. Adjust
    # exponents to be even so that they can be divided in half
    if prec & 1:
        prec += 1
    man = x.man
    exp = x.exp
    if exp & 1:
        exp -= 1
        man <<= 1
    shift = bitcount(man) - prec
    shift -= shift & 1
    man = _rshift(man, shift)
    if prec < 65000:
        man = _sqrt_fixed(man, prec)
    else:
        man = _sqrt_fixed2(man, prec)
    return Float((man, (exp + shift - prec) // 2))
示例#5
0
 def __div__(s, t):
     if t == 0:
         raise ZeroDivisionError
     if isinstance(t, Float):
         sman, sexp, sbc = s
         tman, texp, tbc = t
         extra = max(0, s._prec - sbc + tbc + 4)
         return makefloat((sman<<extra)//tman, sexp-texp-extra)
     if isinstance(t, (int, long)):
         sman, sexp, sbc = s
         extra = s._prec - sbc + bitcount(t) + 4
         return makefloat((sman<<extra)//t, sexp-extra)
     if isinstance(t, (ComplexFloat, complex)):
         return ComplexFloat(s) / t
     return s / Float(t)
示例#6
0
    def __new__(cls, x=0, prec=None, mode=None):
        """
        Float(x) creates a new Float instance with value x. The usual
        types are supported for x:

            >>> Float(3)
            Float('3')
            >>> Float(3.5)
            Float('3.5')
            >>> Float('3.5')
            Float('3.5')
            >>> Float(Rational(7,2))
            Float('3.5')

        You can also create a Float from a tuple specifying its
        mantissa and exponent:

            >>> Float((5, -3))
            Float('0.625')

        Use the prec and mode arguments to specify a custom precision
        level (in bits) and rounding mode. If these arguments are
        omitted, the current working precision is used instead.

            >>> Float('0.500001', prec=3, mode=ROUND_DOWN)
            Float('0.5')
            >>> Float('0.500001', prec=3, mode=ROUND_UP)
            Float('0.625')

        """
        prec = prec or cls._prec
        mode = mode or cls._mode
        if isinstance(x, tuple):
            return tuple.__new__(cls, normalize(x[0], x[1], prec, mode))
        elif isinstance(x, (int, long)):
            return tuple.__new__(cls, normalize(x, 0, prec, mode))
        elif isinstance(x, float):
            # We assume that a float mantissa has 53 bits
            m, e = math.frexp(x)
            return tuple.__new__(cls, normalize(int(m*(1<<53)), e-53, prec, mode))
        elif isinstance(x, (str, Rational)):
            if isinstance(x, str):
                x = Rational(x)
            n = prec + bitcount(x.q) + 2
            return tuple.__new__(cls, normalize((x.p<<n)//x.q, -n, prec, mode))
        else:
            raise TypeError
示例#7
0
def _atan_series_1(x):
    prec = Float._prec
    # Increase absolute precision when extremely close to 0
    bc = bitcount(x.man)
    diff = -(bc + x.exp)
    if diff > 10:
        if 3 * diff - 4 > prec:  # x**3 term vanishes; atan(x) ~x
            return +x
        prec = prec + diff
    prec += 15  # XXX: better estimate for number of guard bits
    x = make_fixed(x, prec)
    x2 = (x * x) >> prec
    one = 1 << prec
    s = a = x
    for n in xrange(1, 1000000):
        a = (a * x2) >> prec
        s += a // ((-1) ** n * (n + n + 1))
        if -100 < a < 100:
            break
    return Float((s, -prec))
示例#8
0
def exp(x):
    """
    exp(x) -- compute the exponential function of the real or complex
    number x
    """
    if isinstance(x, (ComplexFloat, complex)):
        mag = exp(x.real)
        re, im = cos_sin(x.imag)
        return ComplexFloat(mag * re, mag * im)
    else:
        if not isinstance(x, Float):
            x = Float(x)
        # extra precision needs to be similar in magnitude to log_2(|x|)
        prec = Float._prec + 4 + max(0, bitcount(x.man) + x.exp)
        t = make_fixed(x, prec)
        if abs(x) > 1:
            lg2 = log2_fixed(prec)
            n, t = divmod(t, lg2)
        else:
            n = 0
        y = _exp_series(t, prec)
        return Float((y, -prec + n))
示例#9
0
def evalf(expr):
    """
    evalf(expr) attempts to evaluate a SymPy expression to a Float or
    ComplexFloat with an error smaller than 10**(-Float.getdps())
    """

    if isinstance(expr, (Float, ComplexFloat)):
        return expr
    elif isinstance(expr, (int, float)):
        return Float(expr)
    elif isinstance(expr, complex):
        return ComplexFloat(expr)

    expr = Basic.sympify(expr)

    if isinstance(expr, (Rational)):
        y = Float(expr)
    elif isinstance(expr, Real):
        y = Float(str(expr))

    elif expr is I:
        y = ComplexFloat(0,1)

    elif expr is pi:
        y = constants.pi_float()

    elif expr is E:
        y = functions.exp(1)

    elif isinstance(expr, Mul):
        factors = expr[:]
        workprec = Float.getprec() + 1 + len(factors)
        Float.store()
        Float.setprec(workprec)
        y = Float(1)
        for f in factors:
            y *= evalf(f)
        Float.revert()

    elif isinstance(expr, Pow):
        base, expt = expr[:]
        workprec = Float.getprec() + 8 # may need more
        Float.store()
        Float.setprec(workprec)
        base = evalf(base)
        expt = evalf(expt)
        if expt == 0.5:
            y = functions.sqrt(base)
        else:
            y = functions.exp(functions.log(base) * expt)
        Float.revert()

    elif isinstance(expr, Basic.exp):
        Float.store()
        Float.setprec(Float.getprec() + 3)
        #XXX: how is it possible, that this works:
        x = evalf(expr[0])
        #and this too:
        #x = evalf(expr[1])
        #?? (Try to uncomment it and you'll see)
        y = functions.exp(x)
        Float.revert()

    elif isinstance(expr, Add):
        # TODO: this doesn't yet work as it should.
        # We need some way to handle sums whose results are
        # very close to 0, and when necessary, repeat the
        # summation with higher precision
        reqprec = Float.getprec()
        Float.store()
        Float.setprec(10)
        terms = expr[:]
        approxterms = [abs(evalf(x)) for x in terms]
        min_mag = min(x.exp for x in approxterms)
        max_mag = max(x.exp+bitcount(x.man) for x in approxterms)
        Float.setprec(reqprec - 10 + max_mag - min_mag + 1 + len(terms))
        workprec = Float.getdps()
        y = 0
        for t in terms:
            y += evalf(t)
        Float.revert()

    else:
        # print expr, expr.__class__
        raise NotImplementedError

    # print expr, y

    return +y
示例#10
0
def bisect(f, a, b, eps=None, maxsteps=None, verbose=False):
    """
    Numerical root-finding using the bisection method.

    Given a real-valued function f and an interval [a, b] (not
    necessarily real) such that f(a) and f(b) have opposite signs,
    narrow the interval where f crosses the x axis to a relative
    width at most equal to 'eps' through repeated bisections. If
    not specified, eps is set to give a full precision estimate
    of the root.

    A tuple for the narrowed interval is returned.

    If f is continuous, bisect is guaranteed to find a root. If f
    jumps discontinuously from positive negative values, bisect will
    locate the point of the discontinuity. bisect quits early and
    returns an interval of width zero if it encounters a point x
    where f(x) = 0 exactly.

    Optionally, perform no more than 'maxsteps' bisections (by
    default perform as many as needed); if the 'verbose' flag is set,
    print status at each step.

    Examples
    ========

    Find a bounding interval for pi/2 (which is a root of cos):

        >>> Float.setdps(15)
        >>> a, b = bisect(cos, 1, 2, 1e-2, verbose=True)
          bisect step  1: a=1.000000  b=2.000000  delta=1
          bisect step  2: a=1.500000  b=2.000000  delta=0.5
          bisect step  3: a=1.500000  b=1.750000  delta=0.25
          bisect step  4: a=1.500000  b=1.625000  delta=0.125
          bisect step  5: a=1.562500  b=1.625000  delta=0.0625
          bisect step  6: a=1.562500  b=1.593750  delta=0.03125
        >>> print a, b
        1.5625 1.578125

    Calculate the same value to full precision:

        >>> a, b = bisect(cos, 1, 2)
        >>> a, b
        (Float('1.5707963267948966'), Float('1.5707963267948968'))
        >>> print cos(a)
        6.12320117570134E-17
        >>> print cos(b)
        -1.60812593168018E-16

    Although generally reliable, the bisection method has a slow rate
    of convergence. The previous computation required about 50 steps,
    which can be compared to the secant method which only requires
    5-6 steps to obtain a full precision value from an initial value
    near 1.5.
    """

    a, b = a*Float(1), b*Float(1)   # Convert to Float or ComplexFloat
    fa0, fb0 = f(a), f(b)

    # Sanity check
    if not fa0 * fb0 <= 0:
        raise ValueError("bisect: f(a) and f(b) have the same sign at a=%r "
            " and b=%r" %  (a, b))

    fa0sign = sign(fa0)

    # Default eps / set eps to something sane if zero
    mineps = Float((1, -Float.getprec()+1))
    if not eps or eps < mineps:
        eps = mineps

    if maxsteps is None:
        # Use maxsteps as a safeguard should the loop condition fail
        abdelta = abs(a-b)
        maxsteps = bitcount(abdelta.man) - abdelta.exp + Float.getprec()

    i = 1
    while not a.ae(b, eps) and i <= maxsteps:
        if verbose:
            print "  bisect step %2i: a=%8f  b=%8f  delta=%g" % (i,a,b,b-a)
        mid = (a+b)*0.5
        fmid = f(mid)
        if fmid == 0:
            return (mid, mid)
        if sign(fmid) == fa0sign:
            a = mid
        else:
            b = mid
        i += 1

    return a, b