from operator import mul
from fractions import Fraction
import math
n = 5000
def nCk(n,k):
return int( reduce(mul, (Fraction(n-i, i+1) for i in range(k)), 1) )
p = 2.884e-5
totP = 0
sgn = 1
print "n: " + str(n)
for r in range(1, n):
numTerms = nCk(n,r) - ((2*n-3)*(r-1))
totP += sgn * (p ** r) * numTerms
sgn *= -1
print "total = " + str(totP)
当我开始增加n时出现溢出错误:OverflowError:long int太大而无法转换为float
numTerms
字词变得非常大而p^r
字词变得非常小。基本上,我有一个大分子划分一个大分母。关于如何计算这个的任何建议?我已经考虑过使用对数和斯特林的n近似公式!无济于事。任何帮助将不胜感激!
答案 0 :(得分:2)
如果您可以容忍非常轻微的精度损失,您可以使用对数来完全避免除法步骤。根据定义,a/b
等于exp(log(a)-log(b))
。这适用于非常广泛的输入,不会出现上溢或下溢。
要将其放在原始代码的上下文中 - 您有:
return int( reduce(mul, (Fraction(n-i, i+1) for i in range(k)), 1) )
您想要应用的替换是:
[1] a*b --> exp(log(a)+log(b))
[2] c/d --> exp(log(c)-log(d))
所以我相信你的重铸功能看起来像这样:
from operator import add
from math import exp, log
...
return int( exp(reduce(add, (log(n-i)-log(i+1) for i in range(k)), 1)) )
答案 1 :(得分:1)
要处理大精度,您可以使用decimal
库:
import decimal
decimal.getcontext().prec = 100 #Or whatever precision you want...
...
p = decimal.Decimal(2.884e-5)
...
代码很慢,但它还没有在我的电脑上停止......
终于完成了,并意识到:你打印出str(p)
,你永远不会改变它......也许你的意思是totP
?
答案 2 :(得分:0)
我最终使用scipy.misc.comb函数并在浮点值达到'Inf'时设置上限。