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