原始性测试:如何确保不测试已测试数字的倍数的数字?

时间:2017-04-22 12:30:28

标签: python-3.x math

这是我的代码:

from math import sqrt


def isPrime(value):
    a = []
    for i in range(1, int(sqrt(value)) + 1):
        if value <= 3:
            return value
        if value % 2 == 0:
            break
        if value % i == 0:
            a.append(i)
            i += 1
            continue
        elif value % i != 0:
            a = a
            continue
    if len(a) == 1:
        return value
    else:
        pass

我希望能够使用它来测试大数字,但是尽可能快。

2 个答案:

答案 0 :(得分:1)

使用Rabin-Miller算法进行原始性测试

使用Wikipedia: Primality testing

import math


def initial_data(number):
    count = 0
    goree = number - 1
    floor = number // 2
    while goree % 2 == 0:
        goree //= 2
        count += 1
    results = [floor, count]
    return results


def test_values(num):
    test_vals = []
    if num < 2047:
        test_vals = [2]
    elif num < 1373653:
        test_vals = [2, 3]
    elif num < 9080191:
        test_vals = [31, 73]
    elif num < 25326001:
        test_vals = [2, 3, 5]
    elif num < 3215031751:
        test_vals = [2, 3, 5, 7]
    elif num < 4759123141:
        test_vals = [2, 7, 61]
    elif num < 1122004669633:
        test_vals = [2, 13, 23, 1662803]
    elif num < 2152302898747:
        test_vals = [2, 3, 5, 7, 11]
    elif num < 3474749660383:
        test_vals = [2, 3, 5, 7, 11, 13]
    elif num < 341550071728321:
        test_vals = [2, 3, 5, 7, 11, 13, 17]
    elif num < 3825123056546413051:
        test_vals = [2, 3, 5, 7, 11, 13, 17, 19, 23]
    elif num < 2**64:
        test_vals = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
    elif num < 318665857834031151167461:
        test_vals = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37]
    elif num < 3317044064679887385961981:
        test_vals = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41]
    return test_vals


def rabin_miller(num):
    base_primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97,
                   101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197,
                   199, 211, 223, 227, 229, 233, 239,241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
                   317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449,
                   457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521,523, 541, 547, 557, 563, 569, 571, 577, 587,
                   593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661,673, 677, 683, 691, 701, 709,
                   719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853,
                   857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991,
                   997]
    if num <= 1:
        return False
    elif num in base_primes:
        return True
    else:

        for value in base_primes:  # making sure value does not have prime factors in
            if num not in base_primes and num % value == 0:
                return False
        data = initial_data(num)
        s = data[1]
        d = data[0]
        res = False
        testing_values = []
        if num < 3317044064679887385961981:
            testing_values = test_values(num)  # Get values of a to be used from test_values
        else:
            testing_values = [2, min(num - 1, int(2 * (math.log1p(num - 1))**2))]
        for a in testing_values:
            for r in range(1, s + 1):
                power = (2**r)*d

                if pow(a, d, num) != 1 and pow(a, power, num) != 1:
                    res = False

                elif pow(a, d, num) == 1 or pow(a, power, num) == 1:
                    return True
                else:
                    continue
        if res:
            return False
        else:
            return False

print(rabin_miller(5547337572376305111955330958342147474062293202868155909393))

对于大于64位的值,这将非常快速地工作,任何旨在提高准确性和效率(时间效率)代码的提示和注释都是受欢迎的。

  

base_primes列表是使用和改进版本获得的   此问题中的代码:Primality testing: How to make sure not to test numbers which are multiples of already tested numbers?

答案 1 :(得分:0)

以下是随机测试的实现:

import random

#The following function finds s and d in
#n-1 = 2^s*d with d odd

def findSD(n):
    s = 0
    d = n-1
    while d % 2 == 0:
        s = s + 1
        d = d//2
    return s,d

def checkBase(a,n):
    s,d = findSD(n)
    x = pow(a,d,n)
    if x == 1 or x == n-1:
        return "probable prime"
    else:
        for i in range(s-1):
            x = pow(x,2,n)
            if x == 1:
                return "composite"
            elif x == n-1:
                return "probable prime"
        #if you get to this stage, -1 not reached despite s-1
        #squarings -- so must be composite
        return "composite"

def MSR(n,k):
    #tests is an odd number is prime
    for i in range(k):
        a = random.randint(2,n-2)
        if checkBase(a,n) == "composite":
            return "composite"
    #if you get here n has survived k potential witnesses, so
    return "probable prime"

def prime(n):
    smallPrimes = [2,3,5,7,11,13,17,19]

    for p in smallPrimes:
        if n == p:
            return True
        elif n % p == 0:
            return False

    if MSR(n,20) == "composite":
        return False
    else:
        return True

def prime(n):
    smallPrimes = [2,3,5,7,11,13,17,19]

    for p in smallPrimes:
        if n == p:
            return True
        elif n % p == 0:
            return False

    if MSR(n,20) == "composite":
        return False
    else:
        return True

你可以用它捕捉素数:

def findPrime(maxN):
    while True:
        n = random.randint(3,maxN)
        if prime(n):
            return n

典型运行:

>>> findPrime(2**512)
3416363469318261052788311737860856549293100664891633139661459849835325883152102949928216754211470387640525391249585700324869443369023574938398397274187333