为什么 "N choose k" 方法 scipy.misc.comb(n,k) 在 Python2.x 和 Python3.x 之间差异如此之大?

Why does the "N choose k" method, scipy.misc.comb(n,k) differ so much between Python2.x and Python3.x?

在欧拉项目解决问题(剧透)中,这对我来说是一个问题:

15

Python2.7.10 / 0.13.0b1: scipy.misc.comb(40,20) -> array(137846528819.9994)

Python3.5.0 / scipy 0.16.0: scipy.misc.comb(40,20) -> 137846528820.00006

令人沮丧的是,我了解到我必须对结果调用 round() 函数,而不是直接转换为 int() 或使用 math.floor()/math.ceil() 作为 Python 2 / 3 一致性。

是什么导致了两个 Python / SciPy 版本之间的这种差异?

SciPy 开发人员没有首先在 scipy.misc.comb() 内对返回结果调用 round() 有什么原因吗?

如果使用 exact=True 参数,您可以获得相同的整数(长)值。

exact : bool, optional
    If `exact` is False, then floating point precision is used, otherwise
    exact long integer is computed.

我没有安装足够的版本,但我怀疑浮点数差异与版本 13 和 14 之间的代码更改有关。13 returns array(),结果, 14(及更高版本)returns 浮点数 (numpy.float64).

我建议查看 Python 代码本身,看看有什么不同。在 exact 的情况下它们看起来是一样的,但是浮动的情况是完全不同的。

v 13:

    from scipy import special
    k,N = asarray(k), asarray(N)
    lgam = special.gammaln
    cond = (k <= N) & (N >= 0) & (k >= 0)
    sv = special.errprint(0)
    vals = exp(lgam(N+1) - lgam(N-k+1) - lgam(k+1))
    sv = special.errprint(sv)
    return where(cond, vals, 0.0)

v 14

    k,N = asarray(k), asarray(N)
    cond = (k <= N) & (N >= 0) & (k >= 0)
    vals = binom(N, k)
    if isinstance(vals, np.ndarray):
        vals[~cond] = 0
    elif not cond:
        vals = np.float64(0)
    return vals

exact代码是迭代的,可能会比较慢(当N,k在100s时):

    val = 1
    for j in xrange(min(k, N-k)):
        val = (val*(N-j))//(j+1)