如何在python中计算昂贵的高精度和?

如何在python中计算昂贵的高精度和?,python,performance,math,numpy,Python,Performance,Math,Numpy,我的问题很简单。我想计算下面的总数 from __future__ import division from scipy.misc import comb import math for n in xrange(2,1000,10): m = 2.2*n/math.log(n) print sum(sum(comb(n,a) * comb(n-a,b) * (comb(a+b,a)*2**(-a-b))**m for b in xrang

我的问题很简单。我想计算下面的总数

from __future__ import division
from scipy.misc import comb
import math

for n in xrange(2,1000,10):
    m = 2.2*n/math.log(n)
    print sum(sum(comb(n,a) * comb(n-a,b) * (comb(a+b,a)*2**(-a-b))**m
                    for b in xrange(n+1))
               for a in xrange(1,n+1))
但是python给出了
RuntimeWarning:multiply
nan
中遇到的溢出作为输出,而且速度非常慢

有没有一种聪明的方法可以做到这一点?

使用该模式。使用该选项,重新定义梳子:

@memoized
def newcomb(a, b):
    return comb(a, b)
并将对
comb
的所有调用替换为
newcomb
。此外,为了进行细微改进,请拆下支架。如果你做了明确的列表,你就浪费时间去构建它们。如果你删除了它们,你就是在有效地使用它们

更新

这并不能解决
nan
问题,但确实会加快速度


对于所有不认为这是更快的人,您是否正在应用memoize装饰器?在我的机器上,原始功能需要29.7秒才能达到200秒,但记忆版本只需要3.8秒


memoize所做的只是将所有调用的
comb
存储在一个查找表中。因此,如果在以后的迭代中,您使用与过去某个时刻相同的参数调用
comb
,它不会重新计算它-它只是在查找表中查找它。

得到NaN的原因是您最终计算了如下数字

comb(600 + 600, 600) == 3.96509646226102e+359
这太大,无法放入浮点数:

>>> numpy.finfo(float).max
1.7976931348623157e+308
使用对数来避免它:

from __future__ import division, absolute_import, print_function
from scipy.special import betaln
from scipy.misc import logsumexp
import numpy as np


def binomln(n, k):
    # Assumes binom(n, k) >= 0
    return -betaln(1 + n - k, 1 + k) - np.log(n + 1)


for n in range(2, 1000, 10):
    m = 2.2*n/np.log(n)

    a = np.arange(1, n + 1)[np.newaxis,:]
    b = np.arange(n + 1)[:,np.newaxis]

    v = (binomln(n, a) 
         + binomln(n - a, b) 
         + m*binomln(a + b, a) 
         - m*(a+b) * np.log(2))

    term = np.exp(logsumexp(v))
    print(term)

首先,摆脱
[]
;你不需要那些中间列表。comb(n,a)表示n/(a!)*(n-a)!您是否考虑过
cython
?或将
comb
替换为
scipy.special.binom
,并通过对
a=numpy.arange(1,n+1)的向量化求值替换两个内部循环;b=numpy.arange(n+1)
假设前面的问题,首先你不需要像@larsmans说的那样的列表,其次你可以在矩阵中计算梳子,然后在O(1)中检索它。希望能有帮助。你能这样做多大?特别是,它对n=512有帮助吗?虽然我认为它并没有显著加快速度would@Anush:不确定它在512时失败的原因。我修改了你的求幂运算以使用
math.pow
,现在它没有失败,但在512处开始给出NaN。我怀疑有人在表达。也许把它提高到m的力量是罪魁祸首-你可能需要重新设计你的表达来防止这种情况。不知道这个“新来的B”怎么比“梳子”快吗?对于所有不认为这更快的人,你是在应用memoize装饰器吗?在我的机器上,原始功能需要29.7秒才能达到200秒,但记忆版本只需要3.8秒。memoize所做的只是将所有调用的
comb
存储在一个查找表中。因此,如果在以后的迭代中,您使用与过去某个时刻相同的参数调用
comb
,它不会重新计算它-它只是在查找表中查找它。好的。。这就是他们所说的一个非常好的答案。这是一种应该用来宣传自己的东西@是的,右边叫做“热门网络问题”。这就是我如何发现这个简洁的问答。