【问题标题】:Speeding up my Fermat Factorization function (Python)加快我的费马分解函数(Python)
【发布时间】:2012-09-26 00:18:22
【问题描述】:

我的任务是使用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

此代码对于小数字运行得相当快,但对于问题中给出的大数字则需要很长时间。如何提高此代码的速度?我不是在寻找为我编写代码的人,但希望能得到一些建议。感谢您的任何回复。

【问题讨论】:

    标签: python factorization


    【解决方案1】:

    您需要避免进行如此多的平方和平方运算,尤其是在大数上。

    避免它们的简单方法是注意 a^2 - N = b^2 必须为真,所有模数才能成为解决方案。例如,

    a^2 mod 9 - N mod 9 = b^2 mod 9

    假设你的 N 是 55,所以 N mod 9 = 1。

    现在考虑 (a mod 9) 的集合,并将其平方,模 9。 得到的 a^2 mod 9 是集合:{​​0, 1, 4, 7}。 b^2 mod 9 也必须如此。

    如果 a^2 mod 9 = 0,则 0 - 1 = 8(所有 mod 9)不是解,因为 8 不是模 9 的平方数。这消除了 (a mod 9) = {0 , 3 和 6}。

    如果 a^2 mod 9 = 1,则 1 - 1 = 0(所有 mod 9),所以 (a mod 9) = {1, 8} 是可能的解。

    如果 a^2 mod 9 = 4,则 4 - 1 = 3(所有 mod 9)不是可能的解决方案。 同上 a^2 mod 9 = 7。

    因此,一个模数消除了 'a mod 9' 的 9 个可能值中的 7 个。

    你可以有许多个模数,每个模数至少消除一半的可能性。 例如,使用一组 10 个模数,您只需检查大约 1,000 个 a 中的 1 个是否是完美平方或具有整数平方根。 (我的工作使用了大约 10,000 个模数)。

    注意:作为素数幂的模数通常比素数更有用。 此外,模数 16 是一个有用的特殊情况,因为当 N mod 4 为 1 时,“a”必须是奇数, 当 N mod 4 为 3 时,'a' 必须为偶数。“证明留给学生练习。”

    【讨论】:

      【解决方案2】:

      考虑重写此脚本以仅使用整数而不是任意精度的浮点数。

      gmpy 支持整数平方根(返回平方根的下限,有效计算)。这可以用于 is_square() 函数,通过测试平方根的平方是否等于原始值。

      我不确定 gmpy2,但在 gmpy.sqrt() 中需要一个整数参数,并返回一个整数输出。如果您使用浮点数,那么这可能是您的问题(因为与整数相比,浮点数非常慢,尤其是在使用扩展精度时)。如果您实际上使用的是整数,那么每次调用 is_square() 时都必须进行从整数到浮点数的繁琐转换(以及 gmpy2.sqrt() != gmpy.sqrt())。

      对于那些一直说这是一个难题的人,请记住,使用这种方法是一个提示:费马分解算法是基于一个弱点,即当要分解的合数有两个质因数时彼此靠近。如果这是作为提示给出的,那么提出问题的实体很可能知道是这种情况。

      编辑:显然,gmpy2.isqrt() 与 gmpy.sqrt() 相同(sqrt 的整数版本),而 gmpy2.sqrt() 是浮点版本。

      【讨论】:

      • 天哪,这使我的函数快了大约 8 倍!我所要做的就是用gmpy2.isqrt 替换gmpy2.sqrt 并删除gmpy2.ceil。谢谢!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-02
      • 1970-01-01
      相关资源
      最近更新 更多