예제 #1
0
def npartitions(n, verbose=False):
    """
    Calculate the partition function P(n), i.e. the number of ways that
    n can be written as a sum of positive integers.

    P(n) is computed using the Hardy-Ramanujan-Rademacher formula,
    described e.g. at http://mathworld.wolfram.com/PartitionFunctionP.html

    The correctness of this implementation has been tested for 10**n
    up to n = 8.
    """
    n = int(n)
    if n < 0: return 0
    if n <= 5: return [1, 1, 2, 3, 5, 7][n]
    # Estimate number of bits in p(n). This formula could be tidied
    pbits = int((math.pi*(2*n/3.)**0.5-math.log(4*n))/math.log(10)+1)*\
        math.log(10,2)
    prec = p = int(pbits*1.1 + 100)
    s = fzero
    M = max(6, int(0.24*n**0.5+4))
    sq23pi = mpf_mul(mpf_sqrt(from_rational(2,3,p), p), mpf_pi(p), p)
    sqrt8 = mpf_sqrt(from_int(8), p)
    for q in xrange(1, M):
        a = A(n,q,p)
        d = D(n,q,p, sq23pi, sqrt8)
        s = mpf_add(s, mpf_mul(a, d), prec)
        if verbose:
            print "step", q, "of", M, to_str(a, 10), to_str(d, 10)
        # On average, the terms decrease rapidly in magnitude. Dynamically
        # reducing the precision greatly improves performance.
        p = bitcount(abs(to_int(d))) + 50
    np = to_int(mpf_add(s, fhalf, prec))
    return int(np)
예제 #2
0
def D(n, j, prec, sq23pi, sqrt8):
    """
    Compute the sinh term in the outer sum of the HRR formula.
    The constants sqrt(2/3*pi) and sqrt(8) must be precomputed.
    """
    j = from_int(j)
    pi = mpf_pi(prec)
    a = mpf_div(sq23pi, j, prec)
    b = mpf_sub(from_int(n), from_rational(1,24,prec), prec)
    c = mpf_sqrt(b, prec)
    ch, sh = cosh_sinh(mpf_mul(a,c), prec)
    D = mpf_div(mpf_sqrt(j,prec), mpf_mul(mpf_mul(sqrt8,b),pi), prec)
    E = mpf_sub(mpf_mul(a,ch), mpf_div(sh,c,prec), prec)
    return mpf_mul(D, E)
예제 #3
0
파일: numbers.py 프로젝트: gnulinooks/sympy
 def __mul__(self, other):
     try:
         other = _sympify(other)
     except SympifyError:
         return NotImplemented
     if isinstance(other, Number):
         rhs, prec = other._as_mpf_op(self._prec)
         return Real._new(mlib.mpf_mul(self._mpf_, rhs, prec, rnd), prec)
     return Number.__mul__(self, other)
예제 #4
0
 def __mul__(self, other):
     try:
         other = _sympify(other)
     except SympifyError:
         return NotImplemented
     if isinstance(other, Number):
         rhs, prec = other._as_mpf_op(self._prec)
         return Real._new(mlib.mpf_mul(self._mpf_, rhs, prec, rnd), prec)
     return Number.__mul__(self, other)
예제 #5
0
 def __mul__(self, other):
     if isinstance(other, Number):
         rhs, prec = other._as_mpf_op(self._prec)
         return Real._new(mlib.mpf_mul(self._mpf_, rhs, prec, rnd), prec)
     return Number.__mul__(self, other)
예제 #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, 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
예제 #7
0
                if (prec-target_prec) > options.get('maxprec', DEFAULT_MAXPREC):
                    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
예제 #8
0
 def __mul__(self, other):
     if isinstance(other, Number):
         rhs, prec = other._as_mpf_op(self._prec)
         return Real._new(mlib.mpf_mul(self._mpf_, rhs, prec, rnd), prec)
     return Number.__mul__(self, other)
예제 #9
0
파일: evalf.py 프로젝트: fperez/sympy
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