def __neg__(self): return Real._new(mlib.mpf_neg(self._mpf_), self._prec)
def evalf_pow(v, prec, options): target_prec = prec base, exp = v.args # We handle x**n separately. This has two purposes: 1) it is much # faster, because we avoid calling evalf on the exponent, and 2) it # allows better handling of real/imaginary parts that are exactly zero if exp.is_Integer: p = exp.p # Exact if not p: return fone, None, prec, None # Exponentiation by p magnifies relative error by |p|, so the # base must be evaluated with increased precision if p is large prec += int(math.log(abs(p),2)) re, im, re_acc, im_acc = evalf(base, prec+5, options) # Real to integer power if re and not im: return mpf_pow_int(re, p, target_prec), None, target_prec, None # (x*I)**n = I**n * x**n if im and not re: z = fpowi(im, p, target_prec) case = p % 4 if case == 0: return z, None, target_prec, None if case == 1: return None, z, None, target_prec if case == 2: return mpf_neg(z), None, target_prec, None if case == 3: return None, mpf_neg(z), None, target_prec # Zero raised to an integer power if not re: return None, None, None, None # General complex number to arbitrary integer power re, im = libmpc.mpc_pow_int((re, im), p, prec) # Assumes full accuracy in input return finalize_complex(re, im, target_prec) # Pure square root if exp is S.Half: xre, xim, xre_acc, yim_acc = evalf(base, prec+5, options) # General complex square root if xim: re, im = libmpc.mpc_sqrt((xre or fzero, xim), prec) return finalize_complex(re, im, prec) if not xre: return None, None, None, None # Square root of a negative real number if mpf_lt(xre, fzero): return None, mpf_sqrt(mpf_neg(xre), prec), None, prec # Positive square root return mpf_sqrt(xre, prec), None, prec, None # We first evaluate the exponent to find its magnitude # This determines the working precision that must be used prec += 10 yre, yim, yre_acc, yim_acc = evalf(exp, prec, options) # Special cases: x**0 if not (yre or yim): return fone, None, prec, None ysize = fastlog(yre) # Restart if too big # XXX: prec + ysize might exceed maxprec if ysize > 5: prec += ysize yre, yim, yre_acc, yim_acc = evalf(exp, prec, options) # Pure exponential function; no need to evalf the base if base is S.Exp1: if yim: re, im = libmpc.mpc_exp((yre or fzero, yim), prec) return finalize_complex(re, im, target_prec) return mpf_exp(yre, target_prec), None, target_prec, None xre, xim, xre_acc, yim_acc = evalf(base, prec+5, options) # 0**y if not (xre or xim): return None, None, None, None # (real ** complex) or (complex ** complex) if yim: re, im = libmpc.mpc_pow((xre or fzero, xim or fzero), (yre or fzero, yim), target_prec) return finalize_complex(re, im, target_prec) # complex ** real if xim: re, im = libmpc.mpc_pow_mpf((xre or fzero, xim), yre, target_prec) return finalize_complex(re, im, target_prec) # negative ** real elif mpf_lt(xre, fzero): re, im = libmpc.mpc_pow_mpf((xre, fzero), yre, target_prec) return finalize_complex(re, im, target_prec) # positive ** real else: return mpf_pow(xre, yre, target_prec), None, target_prec, None
def evalf_mul(v, prec, options): args = v.args # With guard digits, multiplication in the real case does not destroy # accuracy. This is also true in the complex case when considering the # total accuracy; however accuracy for the real or imaginary parts # separately may be lower. acc = prec target_prec = prec # XXX: big overestimate prec = prec + len(args) + 5 direction = 0 # Empty product is 1 man, exp, bc = MP_BASE(1), 0, 1 direction = 0 complex_factors = [] # First, we multiply all pure real or pure imaginary numbers. # direction tells us that the result should be multiplied by # i**direction for arg in args: re, im, a, aim = evalf(arg, prec, options) if re and im: complex_factors.append((re, im, a, aim)) continue elif re: s, m, e, b = re elif im: a = aim direction += 1 s, m, e, b = im else: return None, None, None, None direction += 2*s man *= m exp += e bc += b if bc > 3*prec: man >>= prec exp += prec acc = min(acc, a) sign = (direction & 2) >> 1 v = normalize(sign, man, exp, bitcount(man), prec, round_nearest) if complex_factors: # Multiply first complex number by the existing real scalar re, im, re_acc, im_acc = complex_factors[0] re = mpf_mul(re, v, prec) im = mpf_mul(im, v, prec) re_acc = min(re_acc, acc) im_acc = min(im_acc, acc) # Multiply consecutive complex factors complex_factors = complex_factors[1:] for wre, wim, wre_acc, wim_acc in complex_factors: re, im, re_acc, im_acc = cmul((re, re_acc), (im,im_acc), (wre,wre_acc), (wim,wim_acc), prec, target_prec) if options.get('verbose'): print "MUL: obtained accuracy", re_acc, im_acc, "expected", target_prec # multiply by i if direction & 1: return mpf_neg(im), re, re_acc, im_acc else: return re, im, re_acc, im_acc else: # multiply by i if direction & 1: return None, v, None, acc else: return v, None, acc, None
return re, im, re_accuracy, im_accuracy prec = prec + max(10+2**i, diff) options['maxprec'] = min(oldmaxprec, 2*prec) if options.get('verbose'): print "ADD: restarting with prec", prec i += 1 finally: options['maxprec'] = oldmaxprec # Helper for complex multiplication # XXX: should be able to multiply directly, and use complex_accuracy # to obtain the final accuracy def cmul((a, aacc), (b, bacc), (c, cacc), (d, dacc), prec, target_prec): A, Aacc = mpf_mul(a,c,prec), min(aacc, cacc) B, Bacc = mpf_mul(mpf_neg(b),d,prec), min(bacc, dacc) C, Cacc = mpf_mul(a,d,prec), min(aacc, dacc) D, Dacc = mpf_mul(b,c,prec), min(bacc, cacc) re, re_accuracy = add_terms([(A, Aacc), (B, Bacc)], prec, target_prec) im, im_accuracy = add_terms([(C, Cacc), (D, Cacc)], prec, target_prec) return re, im, re_accuracy, im_accuracy def evalf_mul(v, prec, options): args = v.args # With guard digits, multiplication in the real case does not destroy # accuracy. This is also true in the complex case when considering the # total accuracy; however accuracy for the real or imaginary parts # separately may be lower. acc = prec target_prec = prec # XXX: big overestimate
def evalf_mul(v, prec, options): args = v.args # With guard digits, multiplication in the real case does not destroy # accuracy. This is also true in the complex case when considering the # total accuracy; however accuracy for the real or imaginary parts # separately may be lower. acc = prec target_prec = prec # XXX: big overestimate prec = prec + len(args) + 5 direction = 0 # Empty product is 1 man, exp, bc = MP_BASE(1), 0, 1 direction = 0 complex_factors = [] # First, we multiply all pure real or pure imaginary numbers. # direction tells us that the result should be multiplied by # i**direction for arg in args: re, im, re_acc, im_acc = evalf(arg, prec, options) if re and im: complex_factors.append((re, im, re_acc, im_acc)) continue elif re: (s, m, e, b), w_acc = re, re_acc elif im: (s, m, e, b), w_acc = im, im_acc direction += 1 else: return None, None, None, None direction += 2*s man *= m exp += e bc += b if bc > 3*prec: man >>= prec exp += prec acc = min(acc, w_acc) sign = (direction & 2) >> 1 v = normalize(sign, man, exp, bitcount(man), prec, round_nearest) if complex_factors: # make existing real scalar look like an imaginary and # multiply by the remaining complex numbers re, im = v, (0, MP_BASE(0), 0, 0) for wre, wim, wre_acc, wim_acc in complex_factors: # acc is the overall accuracy of the product; we aren't # computing exact accuracies of the product. acc = min(acc, complex_accuracy((wre, wim, wre_acc, wim_acc))) A = mpf_mul(re, wre, prec) B = mpf_mul(mpf_neg(im), wim, prec) C = mpf_mul(re, wim, prec) D = mpf_mul(im, wre, prec) re, xre_acc = add_terms([(A, acc), (B, acc)], prec, target_prec) im, xim_acc = add_terms([(C, acc), (D, acc)], prec, target_prec) if options.get('verbose'): print "MUL: wanted", target_prec, "accurate bits, got", acc # multiply by i if direction & 1: return mpf_neg(im), re, acc, acc else: return re, im, acc, acc else: # multiply by i if direction & 1: return None, v, None, acc else: return v, None, acc, None