def _calc_spouge_coefficients(a, prec): """ Calculate Spouge coefficients for approximation with parameter a. Return a list of big integers representing the coefficients in fixed-point form with a precision of prec bits. """ # We'll store the coefficients as fixed-point numbers but calculate # them as Floats for convenience. The initial terms are huge, so we # need to allocate extra bits to ensure full accuracy. The integer # part of the largest term has size ~= exp(a) or 2**(1.4*a) floatprec = prec + int(a*1.4) Float.store() Float.setprec(floatprec) c = [0] * a b = exp(a-1) e = exp(1) c[0] = make_fixed(sqrt(2*pi_float()), prec) for k in range(1, a): # print "%02f" % (100.0 * k / a), "% done" c[k] = make_fixed(((-1)**(k-1) * (a-k)**k) * b / sqrt(a-k), prec) # Divide off e and k instead of computing exp and k! from scratch b = b / (e * k) Float.revert() return c
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