默认情况下,^{}给你一个float64,它溢出并给你inf。
但是如果您传递exact=True,它会给您一个Python变量大小int,它不会溢出(除非您的内存太大而耗尽)。
而且,虽然不能在int上使用np.log2,但是可以使用Python的math.log2。
所以:math.log2(scipy.misc.comb(5000, 2000, exact=True))
作为一种选择,你认为n选择k被定义为n!k / k!,对吗?您可以将其减少到∏(i=1...k)((n+1-i)/i),这是很容易计算的。
或者,如果您想避免溢出,可以通过交替使用* (n-i)和{}来实现。
当然,您也可以将其简化为加减日志。我认为在Python中循环并计算4000个对数将比在C中循环和计算4000个乘法慢,但是我们可以始终将其矢量化,然后,它可能会更快。让我们编写并测试:
^{pr2}$
当然,如果你更关心的是记忆而不是时间…那么,这显然会让事情变得更糟。我们有2000个8字节的浮点值,而不是一次一个608字节的整数。如果你增加到100000,20000,你得到20000个8字节的浮点,而不是一个9K整数。在1000000,200000时,它是200000个8字节浮点值,而不是一个720K整数。
我不知道为什么这两种方式对你来说都是个问题。尤其是考虑到您使用的是listcomp而不是genexpr,因此创建一个包含5000、100000或1000000个Python float-24MB的不必要列表不是问题,但是720K是问题吗?但如果是这样的话,我们显然可以迭代地做同样的事情,但要付出一定的速度:r = sum(math.log2(n-i) - math.log2(k-i) for i in range(n-k))
这并不比scipy解决方案慢得多,而且它使用的字节数永远不会超过一个小的常量(一些Python浮点数)。(除非您使用的是Python2,在这种情况下……只需使用xrange而不是{}并返回常量。)
作为旁注,为什么您使用列表理解而不是带有矢量化操作的NumPy数组(为了速度和紧凑性),或者使用生成器表达式而不是列表理解(根本不占用内存,不需要速度代价)?