处理Python 3中的大数字以计算组合

时间:2016-09-09 13:38:05

标签: python python-3.x

所以我有一个Python 3脚本,以下列方式计算组合

def permutate(n, k):

    if k == 0:
        return 1
    elif n < n - k + 1:
        return n
    else:
        return n * permutate(n - 1, k - 1)


def choose(n, k):

    if k > n / 2:
    k = n - k

    return int(permutate(n, k) / permutate(k, k))

所以我的问题是在处理大数字时,

choose(5, 3)

产生10这是正确的。

choose(1000, 1)
choose(52, 4)
choose(1000, 5)
choose(1000, 999)

这些都会产生正确的结果,但是当我尝试传递

choose(1000, 800)

我得到了错误的结果,我得到的整数的一部分的头是正确的,但是当我到达整数的尾部时它是不正确的,这让我相信问题在于Python试图处理除法选择函数中两个非常大的数字。

return int(permutate(n, k) / permutate(k, k))

对不起,如果我违反了任何规则,或者代码格式化方式如何,正式是我的第一篇帖子:)

3 个答案:

答案 0 :(得分:3)

问题是:你的所有分区都使用浮点数,而它们显然是整数。

Python 3与Python 2的行为不同。

3/2 => 1.5
3//2 => 1

/替换为//(无需像你一样转换整数)

return permutate(n, k) // permutate(k, k)

也在这里(不太重要)

if k > n // 2

答案 1 :(得分:2)

这是另一个解决方案,它使用fractions模块(通过减少到最低项)来进行除法。它还使用了这样的事实: choose(100,70) = choose(100,30)以便不做不必要的乘法:

from fractions import Fraction

def choose(n,k):
    if k > n//2: k = n - k
    p = Fraction(1)
    for i in range(1,k+1):
        p *= Fraction(n - i + 1, i)
    return int(p)

例如,

>>> choose(10000,100)
65208469245472575695415972927215718683781335425416743372210247172869206520770178988927510291340552990847853030615947098118282371982392705479271195296127415562705948429404753632271959046657595132854990606768967505457396473467998111950929802400

(可以用计算机代数系统验证)。

速度相当快,需要大约一秒才能找到choose(10**9, 10000)的所有54341位数字。

答案 2 :(得分:0)

编辑正确/简洁

我有另一种方法可以减轻分裂的负担,并将其放在乘法上。我建议利用组合的定义。由于组合和排列是计数技术,因此通过算术运算失去精度并不是很好的工艺。

在组合中,你想尽可能地取消分子和分母中的公因子,以便你可以。所以我说完全抛弃了你的排列函数,你的组合函数就像... ...

    def permute(n, k):
        // P(n,k) = n!/(n-k)!  mathematically
        largest_dividable_number = max(k, n-k)
        output_value = 1
        starting_value = n
        for i in range(1,largest_dividable_number - 1):
            output_value = output_value * starting_value
            starting_value = starting_value - 1
        return output_value

    def choose(n, k):
        p = permute(n,k)
        return p//math.factorial(k)