我的任务是使用Fermat's factorization method计算非常大的复合数。这些数字是1024位大,大约是309个十进制数字。
我已经提出了下面的Python代码,它使用gmpy2
模块来提高准确性。它只是Wikipedia page上显示的伪代码的Python实现。我在该页面上阅读了“Sieve Improvement”部分,但不确定如何实施它。
def fermat_factor(n):
assert n % 2 != 0 # Odd integers only
a = gmpy2.ceil(gmpy2.sqrt(n))
b2 = gmpy2.square(a) - n
while not is_square(b2):
a += 1
b2 = gmpy2.square(a) - n
factor1 = a + gmpy2.sqrt(b2)
factor2 = a - gmpy2.sqrt(b2)
return int(factor1), int(factor2)
def is_square(n):
root = gmpy2.sqrt(n)
return root % 1 == 0 # '4.0' will pass, '4.1212' won't
对于小数字,此代码运行速度相当快,但对于与问题中给出的数字一样大的数字需要花费太长时间。如何提高此代码的速度?我不是在找人为我编写代码,但我会很感激一些建议。感谢您的回复。
答案 0 :(得分:4)
你需要避免做那么多的square和sqrt操作,特别是在大数字上。
避免它们的简单方法是注意,对于所有模数来说,^ 2 - N = b ^ 2必须为真。例如,
a ^ 2 mod 9 - N mod 9 = b ^ 2 mod 9
假设你的N是55,所以N mod 9 = 1。
现在考虑(一个mod 9)的集合,并将它取平方,模9。 得到的^ 2 mod 9是集合:{0,1,4,7}。对于b ^ 2 mod 9也必须如此。
如果^ 2 mod 9 = 0,则0 - 1 = 8(所有mod 9)不是解,因为8不是数模9的平方。这消除了(a mod 9)= {0 ,3和6}。
如果^ 2 mod 9 = 1,则1 - 1 = 0(所有mod 9),因此(a mod 9)= {1,8}是可能的解决方案。
如果^ 2 mod 9 = 4,则4 - 1 = 3(所有mod 9)不是可能的解决方案。 同上为^ 2 mod 9 = 7.
因此,一个模数消除了'a mod 9'的9个可能值中的7个。
你可以拥有许多模数,每一个都消除了至少一半的可能性。 使用一组,比方说,10个模数,你只需要检查大约1/1000 a的完美正方形,或者具有整数平方根。 (我的工作使用了大约10,000个模数。)
注意:作为素数幂的模数通常比素数更有用。 此外,模数16是一个有用的特殊情况,因为当N mod 4为1时,'a'必须是奇数, 当N mod 4为3时,'a'必须均匀。“证明留给学生练习。”
答案 1 :(得分:3)
考虑重写此脚本以仅使用整数而不是任意精度浮点数。
gmpy支持整数平方根(返回平方根的底数,有效计算)。这可以通过测试平方根的平方是否等于原始值来用于is_square()函数。
我不确定gmpy2,但是在gmpy.sqrt()中需要一个整数参数,并返回一个整数输出。如果你使用浮点数,那么这可能是你的问题(因为浮点数与整数相比非常慢,特别是在使用扩展精度时)。如果你实际上使用整数,那么is_square()每次调用时都必须进行从整数到浮点的繁琐转换(和gmpy2.sqrt()!= gmpy.sqrt())。
对于那些一直说这是一个难题的人,请记住,使用这种方法是一个暗示:fermat分解算法基于当要考虑的复合数具有两个素因子时存在的弱点彼此接近。如果这是作为提示给出的,则构成问题的实体很可能知道这种情况。
编辑:显然,gmpy2.isqrt()与gmpy.sqrt()(sqrt的整数版本)相同,gmpy2.sqrt()是浮点版本。