使用GMPY2(或GMP)找到所有因子的最有效方法是什么?

时间:2014-05-17 05:46:32

标签: python factorization gmpy

我知道那里已经有类似的问题了,但我想用GMPY2(或与GMP类似的东西)来加快速度。 这是我目前的代码,它是不错的但可以更好吗?

编辑:新代码,检查除数2和3

def factors(n):
    result = set()
    result |= {mpz(1), mpz(n)}


    def all_multiples(result, n, factor):
        z = mpz(n)
        while gmpy2.f_mod(mpz(z), factor) == 0:
            z = gmpy2.divexact(z, factor)
            result |= {mpz(factor), z}
        return result

    result = all_multiples(result, n, 2)
    result = all_multiples(result, n, 3)

    for i in range(1, gmpy2.isqrt(n) + 1, 6):
        i1 = mpz(i) + 1
        i2 = mpz(i) + 5
        div1, mod1 = gmpy2.f_divmod(n, i1)
        div2, mod2 = gmpy2.f_divmod(n, i2)
        if mod1 == 0:
            result |= {i1, div1}
        if mod2 == 0:
            result |= {i2, div2}
    return result

如果可能的话,我也只对n^(1/3) and 2^(2/3)*n(1/3)

内的除数实施感兴趣

例如,mathematica的factor()比python代码快得多。我想要将20到50位十进制数之间的数字。我知道ggnfs可以在不到5秒的时间内考虑这些因素。

我感兴趣的是,在python中是否存在实现快速因子分解的任何模块。

1 个答案:

答案 0 :(得分:4)

我只是对您的代码进行了一些快速更改,以消除冗余的名称查找。算法仍然相同,但它在我的计算机上快了两倍。

import gmpy2
from gmpy2 import mpz

def factors(n):
    result = set()
    n = mpz(n)
    for i in range(1, gmpy2.isqrt(n) + 1):
        div, mod = divmod(n, i)
        if not mod:
            result |= {mpz(i), div}
    return result

print(factors(12345678901234567))

其他建议需要有关数字大小的更多信息等。例如,如果您需要所有可能的因素,那么从所有主要因素构建这些因素可能会更快。这种方法可以让你在继续时减少范围语句的限制,也可以让你增加2(删除​​2的所有因子后)。

更新1

我对您的代码进行了一些其他更改。我不认为你的all_multiplies()功能是正确的。您的range()声明不是最佳的,因为2再次检查,但我的第一次修复使情况变得更糟。

新代码延迟计算辅助因子,直到它知道余数为0.我还尝试尽可能多地使用内置函数。例如,mpz % integer比gmpy2.f_mod(mpz,integer)或gmpy2.f_mod(integer,mpz)快,其中integer是普通的Python整数。

import gmpy2
from gmpy2 import mpz, isqrt

def factors(n):
    n = mpz(n)

    result = set()
    result |= {mpz(1), n}

    def all_multiples(result, n, factor):
        z = n
        f = mpz(factor)
        while z % f == 0:
            result |= {f, z // f}
            f += factor
        return result

    result = all_multiples(result, n, 2)
    result = all_multiples(result, n, 3)

    for i in range(1, isqrt(n) + 1, 6):
        i1 = i + 1
        i2 = i + 5
        if not n % i1:
            result |= {mpz(i1), n // i1}
        if not n % i2:
            result |= {mpz(i2), n // i2}
    return result

print(factors(12345678901234567))

我会改变你的程序,只是找到小于n的平方根的所有素因子,然后再构造所有的辅因子。然后,每当您找到一个因素时,我会减少n,检查n是否为素数,并且仅在n不是素数时才查找更多因素。

更新2

pyecm模块应该能够计算您要考虑的大小数量。以下示例在大约一秒钟内完成。

>>> import pyecm
>>> list(pyecm.factors(12345678901234567890123456789012345678901, False, True, 10, 1))
[mpz(29), mpz(43), mpz(43), mpz(55202177), mpz(2928109491677), mpz(1424415039563189)]