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))
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
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))
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))
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)
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
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))
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))
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
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