我的PollardP1_rho代码有问题,但我不知道如何解决它

时间:2016-12-08 09:50:34

标签: algorithm python-3.x prime-factoring

我尝试使用MillerRabin + PollardP1_rho方法将整数分解为Python3中的素数,以尽可能地减少时间复杂度。但是它失败了一些测试,我知道问题在哪里。但我是算法中的tyro,我不知道如何解决它。所以我会把所有相关代码放在这里。

import random

def gcd(a, b):
    """
    a, b: integers
    returns: a positive integer, the greatest common divisor of a & b.
    """
    if a == 0:
        return b
    if a < 0:
        return gcd(-a, b)
    while b > 0:
        c = a % b
        a, b = b, c
    return a

def mod_mul(a, b, n):
    # Calculate a * b % n iterately.
    result = 0
    while b > 0:
        if (b & 1) > 0:
            result = (result + a) % n
        a = (a + a) % n
        b = (b >> 1)
    return result

def mod_exp(a, b, n):
    # Calculate (a ** b) % n iterately.
    result = 1
    while b > 0:
        if (b & 1) > 0:
            result = mod_mul(result, a, n)
        a = mod_mul(a, a, n)
        b = (b >> 1)
    return result

def MillerRabinPrimeCheck(n):
    if n in {2, 3, 5, 7, 11}:
        return True
    elif (n == 1 or n % 2 == 0 or n % 3 == 0 or n % 5 == 0 or n % 7 == 0 or n % 11 == 0):
        return False
    k = 0
    u = n - 1
    while not (u & 1) > 0:
        k += 1
        u = (u >> 1)
    random.seed(0)
    s = 5 #If the result isn't right, then add the var s.
    for i in range(s):
        x = random.randint(2, n - 1)
        if x % n == 0:
            continue
        x = mod_exp(x, u, n)
        pre = x
        for j in range(k):
            x = mod_mul(x, x, n)
            if (x == 1 and pre != 1 and pre != n - 1):
                return False
            pre = x
        if x != 1:
            return False
        return True

def PollardP1_rho(n, c):
    '''
    Consider c as a constant integer.
    ''' 
    i = 1
    k = 2
    x = random.randrange(1, n - 1) + 1
    y = x
    while 1:
        i += 1
        x = (mod_mul(x, x, n) + c) % n
        d = gcd(y - x, n)
        if 1 < d < n:
            return d
        elif x == y:
            return n
        elif i == k:
            y = x
            k = (k << 1)

result = []
def PrimeFactorsListGenerator(n):
    if n <= 1:
        pass
    elif MillerRabinPrimeCheck(n) == True:
        result.append(n)
    else:
        a = n
        while a == n:
            a = PollardP1_rho(n, random.randrange(1,n - 1) + 1)
        PrimeFactorsListGenerator(a)
        PrimeFactorsListGenerator(n // a)

当我试图测试时:

PrimeFactorsListGenerator(4)

它没有停止并循环这个:

PollardP1_rho(4, random.randrange(1,4 - 1) + 1)

我已经在PollardP1_rho之前测试了它们的功能并且它们正常工作,所以我知道PollardP1_rho函数无法正确处理数字4,也就是数字5.我怎么能解决这个问题?

1 个答案:

答案 0 :(得分:0)

我自己解决了。 代码中有1个错误。 我不应该使用var&#39;结果&#39;在作为全局变量的函数之外,我应该在函数中定义并使用result.extend()来确保整个递归过程的可用性。所以我重写了PollardP1_rho(n,c)和PrimeFactorsListGenerator(n):

def Pollard_rho(x, c):
    '''
    Consider c as a constant integer.
    ''' 
    i, k = 1, 2
    x0 = random.randint(0, x)
    y = x0
    while 1:
        i += 1
        x0 = (mod_mul(x0, x0, x) + c) % x
        d = gcd(y - x0, x)
        if d != 1 and d != x:
            return d
        if y == x0:
            return x
        if i == k:
            y = x0
            k += k

def PrimeFactorsListGenerator(n):
    result = []
    if n <= 1:
        return None
    if MillerRabinPrimeCheck(n):
        return [n]
    p = n
    while p >= n:
        p = Pollard_rho(p, random.randint(1, n - 1))
    result.extend(PrimeFactorsListGenerator(p))
    result.extend(PrimeFactorsListGenerator(n // p))
    return result

#PrimeFactorsListGenerator(400)
#PrimeFactorsListGenerator(40000)

还有一个提示:您根本不需要使用Python内置的pow(a,b,n)编写函数mod_mul(a,b,n) )将完成这一诀窍,并进行全面优化。