我知道那里已经有类似的问题了,但我想用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中是否存在实现快速因子分解的任何模块。
答案 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)]