【问题标题】:Why is my implementation of the Miller-Rabin algorithm not able to detect some primes?为什么我的 Miller-Rabin 算法实现无法检测到某些素数?
【发布时间】:2019-03-31 17:15:39
【问题描述】:

我正在尝试为一些正在运行的项目实施Miller-Rabin primality checker。但是,该算法不适用于诸如 101、103、107、109 之类的素数……我不知道问题出在哪里。提前感谢所有帮助。

def miller_rabin_is_prime(number, k=10):

    if number < 2:
        return False
    elif number <= 3:
        return True

    else:
        odd_num, power_of_two, factor_out = 0, 0, number - 1

        while number != (2 ** power_of_two)*odd_num + 1:
            if factor_out / 2 == int(factor_out / 2):
                power_of_two += 1
                factor_out /= 2
            else:
                odd_num = (number - 1) / (2 ** power_of_two)

        for _ in range(k):
            random = randint(2, number - 2)
            checker = (random**odd_num) % number

            if (checker == 1) or (checker == number - 1):
                continue
            try:
                for loop in range(power_of_two - 1):
                    checker = (checker**2) % number
                    if checker == number - 1:
                        raise TypeError
            except TypeError:
                continue
            return False

        return True

我希望 101 的输出为 True,但实际输出为 False。

【问题讨论】:

  • 注: if factor_out / 2 == int(factor_out / 2) 可分性检查可以由if factor_out % 2 == 0 完成。 (% 是模运算符。)
  • 不要使用浮点除法。这没有道理。要查看整数 x 是否可以被整数 y 整除,只需使用 x % y == 0。如果你真的想将它们分开,请使用整数除法(由双斜杠指定),即x // y
  • 天啊。真对不起。我完全忘记了。你是对的。

标签: python python-3.x math primes


【解决方案1】:

如果你替换

 odd_num = (number - 1) / (2 ** power_of_two)

通过

 odd_num = (number - 1) // (2 ** power_of_two)

您的代码可以工作——但对于较大的数字会相当缓慢。改进代码:

  1. 使用更简单的方法计算odd_numpower_of_two
  2. 使用pow() 进行模幂运算。

类似:

from random import randint
def miller_rabin_is_prime(number, k=10):

    if number < 2:
        return False
    elif number <= 3:
        return True

    else:
        odd_num = number - 1
        power_of_two = 0

        while odd_num % 2 == 0:
            power_of_two += 1
            odd_num //= 2

        for _ in range(k):
            random = randint(2, number - 2)
            checker = pow(random,odd_num, number)

            if (checker == 1) or (checker == number - 1):
                continue
            try:
                for loop in range(power_of_two - 1):
                    checker = pow(checker,2,number)
                    if checker == number - 1:
                        raise TypeError
            except TypeError:
                continue
            return False

        return True

然后,例如,miller_rabin_is_prime(1000003) 将几乎立即计算为 True,而您的原始代码(即使在 /// 替换后)由于非模幂运算需要大约 15 秒。

作为最后的评论,您正在对非错误条件使用错误处理(显然checker == number - 1 时没有类型错误)。重构主循环使其不使用try--except 会更干净。错误处理不适用于普通的控制流。

【讨论】:

  • 非常感谢您的深入解释:)
猜你喜欢
  • 1970-01-01
  • 2021-07-05
  • 1970-01-01
  • 2016-02-27
  • 1970-01-01
  • 1970-01-01
  • 2013-06-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多