def add_terms(terms, prec, target_prec): """ Helper for evalf_add. Adds a list of (mpfval, accuracy) terms. """ if len(terms) == 1: if not terms[0]: # XXX: this is supposed to represent a scaled zero return mpf_shift(fone, target_prec), -1 return terms[0] max_extra_prec = 2*prec sum_man, sum_exp, absolute_error = 0, 0, MINUS_INF for x, accuracy in terms: if not x: continue sign, man, exp, bc = x if sign: man = -man absolute_error = max(absolute_error, bc+exp-accuracy) delta = exp - sum_exp if exp >= sum_exp: # x much larger than existing sum? # first: quick test if (delta > max_extra_prec) and \ ((not sum_man) or delta-bitcount(abs(sum_man)) > max_extra_prec): sum_man = man sum_exp = exp else: sum_man += (man << delta) else: delta = -delta # x much smaller than existing sum? if delta-bc > max_extra_prec: if not sum_man: sum_man, sum_exp = man, exp else: sum_man = (sum_man << delta) + man sum_exp = exp if absolute_error == MINUS_INF: return None, None if not sum_man: # XXX: this is supposed to represent a scaled zero return mpf_shift(fone, absolute_error), -1 if sum_man < 0: sum_sign = 1 sum_man = -sum_man else: sum_sign = 0 sum_bc = bitcount(sum_man) sum_accuracy = sum_exp + sum_bc - absolute_error r = normalize(sum_sign, sum_man, sum_exp, sum_bc, target_prec, round_nearest), sum_accuracy #print "returning", to_str(r[0],50), r[1] return r
def add_terms(terms, prec, target_prec): """ Helper for evalf_add. Adds a list of (mpfval, accuracy) terms. """ if len(terms) == 1: if not terms[0]: # XXX: this is supposed to represent a scaled zero return mpf_shift(fone, target_prec), -1 return terms[0] max_extra_prec = 2 * prec sum_man, sum_exp, absolute_error = 0, 0, MINUS_INF for x, accuracy in terms: if not x: continue sign, man, exp, bc = x if sign: man = -man absolute_error = max(absolute_error, bc + exp - accuracy) delta = exp - sum_exp if exp >= sum_exp: # x much larger than existing sum? # first: quick test if (delta > max_extra_prec) and \ ((not sum_man) or delta-bitcount(abs(sum_man)) > max_extra_prec): sum_man = man sum_exp = exp else: sum_man += (man << delta) else: delta = -delta # x much smaller than existing sum? if delta - bc > max_extra_prec: if not sum_man: sum_man, sum_exp = man, exp else: sum_man = (sum_man << delta) + man sum_exp = exp if absolute_error == MINUS_INF: return None, None if not sum_man: # XXX: this is supposed to represent a scaled zero return mpf_shift(fone, absolute_error), -1 if sum_man < 0: sum_sign = 1 sum_man = -sum_man else: sum_sign = 0 sum_bc = bitcount(sum_man) sum_accuracy = sum_exp + sum_bc - absolute_error r = normalize(sum_sign, sum_man, sum_exp, sum_bc, target_prec, round_nearest), sum_accuracy #print "returning", to_str(r[0],50), r[1] return r
def finalize_complex(re, im, prec): assert re and im if re == fzero and im == fzero: raise ValueError("got complex zero with unknown accuracy") size_re = fastlog(re) size_im = fastlog(im) # Convert fzeros to scaled zeros if re == fzero: re = mpf_shift(fone, size_im-prec) size_re = fastlog(re) elif im == fzero: im = mpf_shift(fone, size_re-prec) size_im = fastlog(im) if size_re > size_im: re_acc = prec im_acc = prec + min(-(size_re - size_im), 0) else: im_acc = prec re_acc = prec + min(-(size_im - size_re), 0) return re, im, re_acc, im_acc
def finalize_complex(re, im, prec): assert re and im if re == fzero and im == fzero: raise ValueError("got complex zero with unknown accuracy") size_re = fastlog(re) size_im = fastlog(im) # Convert fzeros to scaled zeros if re == fzero: re = mpf_shift(fone, size_im - prec) size_re = fastlog(re) elif im == fzero: im = mpf_shift(fone, size_re - prec) size_im = fastlog(im) if size_re > size_im: re_acc = prec im_acc = prec + min(-(size_re - size_im), 0) else: im_acc = prec re_acc = prec + min(-(size_im - size_re), 0) return re, im, re_acc, im_acc
def scaled_zero(mag, sign=1): """Return an mpf representing a power of two with magnitude ``mag`` and -1 for precision. Or, if ``mag`` is a scaled_zero tuple, then just remove the sign from within the list that it was initially wrapped in. Examples ======== >>> from sympy.core.evalf import scaled_zero >>> from sympy import Float >>> z, p = scaled_zero(100) >>> z, p (([0], 1, 100, 1), -1) >>> ok = scaled_zero(z) >>> ok (0, 1, 100, 1) >>> Float(ok) 1.26765060022823e+30 >>> Float(ok, p) 0.e+30 >>> ok, p = scaled_zero(100, -1) >>> Float(scaled_zero(ok), p) -0.e+30 """ if type(mag) is tuple and len(mag) == 4 and iszero(mag, scaled=True): return (mag[0][0],) + mag[1:] elif isinstance(mag, SYMPY_INTS): if sign not in [-1, 1]: raise ValueError("sign must be +/-1") rv, p = mpf_shift(fone, mag), -1 s = 0 if sign == 1 else 1 rv = ([s],) + rv[1:] return rv, p else: raise ValueError("scaled zero expects int or scaled_zero tuple.")
def scaled_zero(mag, sign=1): """Return an mpf representing a power of two with magnitude ``mag`` and -1 for precision. Or, if ``mag`` is a scaled_zero tuple, then just remove the sign from within the list that it was initially wrapped in. Examples ======== >>> from sympy.core.evalf import scaled_zero >>> from sympy import Float >>> z, p = scaled_zero(100) >>> z, p (([0], 1, 100, 1), -1) >>> ok = scaled_zero(z) >>> ok (0, 1, 100, 1) >>> Float(ok) 1.26765060022823e+30 >>> Float(ok, p) 0.e+30 >>> ok, p = scaled_zero(100, -1) >>> Float(scaled_zero(ok), p) -0.e+30 """ if type(mag) is tuple and len(mag) == 4 and iszero(mag, scaled=True): return (mag[0][0],) + mag[1:] elif isinstance(mag, SYMPY_INTS): if sign not in [-1, 1]: raise ValueError('sign must be +/-1') rv, p = mpf_shift(fone, mag), -1 s = 0 if sign == 1 else 1 rv = ([s],) + rv[1:] return rv, p else: raise ValueError('scaled zero expects int or scaled_zero tuple.')
def do_integral(expr, prec, options): func = expr.args[0] x, xlow, xhigh = expr.args[1] orig = mp.prec oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC) options['maxprec'] = min(oldmaxprec, 2*prec) try: mp.prec = prec+5 xlow = as_mpmath(xlow, prec+15, options) xhigh = as_mpmath(xhigh, prec+15, options) # Integration is like summation, and we can phone home from # the integrand function to update accuracy summation style # Note that this accuracy is inaccurate, since it fails # to account for the variable quadrature weights, # but it is better than nothing have_part = [False, False] max_real_term = [MINUS_INF] max_imag_term = [MINUS_INF] def f(t): re, im, re_acc, im_acc = evalf(func, mp.prec, {'subs':{x:t}}) have_part[0] = re or have_part[0] have_part[1] = im or have_part[1] max_real_term[0] = max(max_real_term[0], fastlog(re)) max_imag_term[0] = max(max_imag_term[0], fastlog(im)) if im: return mpc(re or fzero, im) return mpf(re or fzero) if options.get('quad') == 'osc': A = C.Wild('A', exclude=[x]) B = C.Wild('B', exclude=[x]) D = C.Wild('D') m = func.match(C.cos(A*x+B)*D) if not m: m = func.match(C.sin(A*x+B)*D) if not m: raise ValueError("An integrand of the form sin(A*x+B)*f(x) " "or cos(A*x+B)*f(x) is required for oscillatory quadrature") period = as_mpmath(2*S.Pi/m[A], prec+15, options) result = quadosc(f, [xlow, xhigh], period=period) # XXX: quadosc does not do error detection yet quadrature_error = MINUS_INF else: result, quadrature_error = quadts(f, [xlow, xhigh], error=1) quadrature_error = fastlog(quadrature_error._mpf_) finally: options['maxprec'] = oldmaxprec mp.prec = orig if have_part[0]: re = result.real._mpf_ if re == fzero: re = mpf_shift(fone, min(-prec,-max_real_term[0],-quadrature_error)) re_acc = -1 else: re_acc = -max(max_real_term[0]-fastlog(re)-prec, quadrature_error) else: re, re_acc = None, None if have_part[1]: im = result.imag._mpf_ if im == fzero: im = mpf_shift(fone, min(-prec,-max_imag_term[0],-quadrature_error)) im_acc = -1 else: im_acc = -max(max_imag_term[0]-fastlog(im)-prec, quadrature_error) else: im, im_acc = None, None result = re, im, re_acc, im_acc return result
def do_integral(expr, prec, options): func = expr.args[0] x, xlow, xhigh = expr.args[1] orig = mp.prec oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC) options['maxprec'] = min(oldmaxprec, 2 * prec) try: mp.prec = prec + 5 xlow = as_mpmath(xlow, prec + 15, options) xhigh = as_mpmath(xhigh, prec + 15, options) # Integration is like summation, and we can phone home from # the integrand function to update accuracy summation style # Note that this accuracy is inaccurate, since it fails # to account for the variable quadrature weights, # but it is better than nothing have_part = [False, False] max_real_term = [MINUS_INF] max_imag_term = [MINUS_INF] def f(t): re, im, re_acc, im_acc = evalf(func, mp.prec, {'subs': {x: t}}) have_part[0] = re or have_part[0] have_part[1] = im or have_part[1] max_real_term[0] = max(max_real_term[0], fastlog(re)) max_imag_term[0] = max(max_imag_term[0], fastlog(im)) if im: return mpc(re or fzero, im) return mpf(re or fzero) if options.get('quad') == 'osc': A = C.Wild('A', exclude=[x]) B = C.Wild('B', exclude=[x]) D = C.Wild('D') m = func.match(C.cos(A * x + B) * D) if not m: m = func.match(C.sin(A * x + B) * D) if not m: raise ValueError( "An integrand of the form sin(A*x+B)*f(x) " "or cos(A*x+B)*f(x) is required for oscillatory quadrature" ) period = as_mpmath(2 * S.Pi / m[A], prec + 15, options) result = quadosc(f, [xlow, xhigh], period=period) # XXX: quadosc does not do error detection yet quadrature_error = MINUS_INF else: result, quadrature_error = quadts(f, [xlow, xhigh], error=1) quadrature_error = fastlog(quadrature_error._mpf_) finally: options['maxprec'] = oldmaxprec mp.prec = orig if have_part[0]: re = result.real._mpf_ if re == fzero: re = mpf_shift(fone, min(-prec, -max_real_term[0], -quadrature_error)) re_acc = -1 else: re_acc = -max(max_real_term[0] - fastlog(re) - prec, quadrature_error) else: re, re_acc = None, None if have_part[1]: im = result.imag._mpf_ if im == fzero: im = mpf_shift(fone, min(-prec, -max_imag_term[0], -quadrature_error)) im_acc = -1 else: im_acc = -max(max_imag_term[0] - fastlog(im) - prec, quadrature_error) else: im, im_acc = None, None result = re, im, re_acc, im_acc return result