Ejemplo n.º 1
0
 def __neg__(self):
     return Real._new(mlib.mpf_neg(self._mpf_), self._prec)
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
                    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
Ejemplo n.º 5
0
 def __neg__(self):
     return Real._new(mlib.mpf_neg(self._mpf_), self._prec)
Ejemplo n.º 6
0
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