简体   繁体   English

快速确定Python中的数字是否为数字<10亿

[英]Quickly determine if a number is prime in Python for numbers < 1 billion

My current algorithm to check the primality of numbers in python is way to slow for numbers between 10 million and 1 billion. 我目前用于检查python中数字素数的算法可以减慢1000万到10亿之间的数字。 I want it to be improved knowing that I will never get numbers bigger than 1 billion. 我希望它得到改善,因为我知道我永远不会得到超过10亿的数字。

The context is that I can't get an implementation that is quick enough for solving problem 60 of project Euler: I'm getting the answer to the problem in 75 seconds where I need it in 60 seconds. 上下文是我无法获得足够快的解决方案来解决项目Euler的问题60:我在75秒内得到问题的答案,我需要在60秒内完成。 http://projecteuler.net/index.php?section=problems&id=60 http://projecteuler.net/index.php?section=problems&id=60

I have very few memory at my disposal so I can't store all the prime numbers below 1 billion. 我的内存很少,所以我无法存储10亿以下的所有素数。

I'm currently using the standard trial division tuned with 6k±1. 我目前正在使用以6k±1调谐的标准试验部门。 Is there anything better than this? 还有什么比这更好的吗? Do I already need to get the Rabin-Miller method for numbers that are this large. 我是否已经需要使用Rabin-Miller方法来获得如此大的数字。

primes_under_100 = [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]
def isprime(n):
    if n <= 100:
        return n in primes_under_100
    if n % 2 == 0 or n % 3 == 0:
        return False

    for f in range(5, int(n ** .5), 6):
        if n % f == 0 or n % (f + 2) == 0:
            return False
    return True

How can I improve this algorithm? 如何改进此算法?

Precision: I'm new to python and would like to work with python 3+ only. 精度:我是python的新手,只想使用python 3+。


Final code 最终代码

For those who are interested, using MAK's ideas, I generated the following code which is about 1/3 quicker, allowing me to get the result of the euler problem in less than 60 seconds! 对于那些感兴趣的人,使用MAK的想法,我生成了以下代码,大约快1/3,让我在不到60秒的时间内得到欧拉问题的结果!

from bisect import bisect_left
# sqrt(1000000000) = 31622
__primes = sieve(31622)
def is_prime(n):
    # if prime is already in the list, just pick it
    if n <= 31622:
        i = bisect_left(__primes, n)
        return i != len(__primes) and __primes[i] == n
    # Divide by each known prime
    limit = int(n ** .5)
    for p in __primes:
        if p > limit: return True
        if n % p == 0: return False
    # fall back on trial division if n > 1 billion
    for f in range(31627, limit, 6): # 31627 is the next prime
        if n % f == 0 or n % (f + 4) == 0:
            return False
    return True

For numbers as large as 10^9, one approach can be to generate all primes up to sqrt(10^9) and then simply check the divisibility of the input number against the numbers in that list. 对于大到10 ^ 9的数字,一种方法可以生成直到sqrt(10 ^ 9)的所有素数,然后简单地检查输入数与该列表中的数字的可分性。 If a number isn't divisible by any other prime less than or equal to its square root, it must itself be a prime (it must have at least one factor <=sqrt and another >= sqrt to not be prime). 如果一个数字不能被小于或等于其平方根的任何其他素数整除,则它本身必须是一个素数(它必须至少有一个因子<= sqrt而另一个> = sqrt才能成为素数)。 Notice how you do not need to test divisibility for all numbers, just up to the square root (which is around 32,000 - quite manageable I think). 请注意你不需要测试所有数字的可分性,只需要达到平方根(大约32,000 - 我认为非常容易管理)。 You can generate the list of primes using a sieve . 您可以使用筛子生成素数列表。

You could also go for a probabilistic prime test . 你也可以去进行概率素数测试 But they can be harder to understand, and for this problem simply using a generated list of primes should suffice. 但是它们可能更难理解,对于这个问题,仅仅使用生成的素数列表就足够了。

For solving Project Euler problems I did what you suggest in your question: Implement the Miller Rabin test (in C# but I suspect it will be fast in Python too). 为了解决Project Euler问题,我在你的问题中做了你的建议:实现Miller Rabin测试(在C#中,但我怀疑它在Python中也会很快)。 The algorithm is not that difficult. 算法并不困难。 For numbers below 4,759,123,141 it is enough to check that a number is a strong pseudo prime to the bases 2, 7, 61. Combine that with trial division by small primes. 对于低于4,759,123,141的数字,足以检查一个数字是基数2,7,61的强伪素数。将其与小数的试验除法相结合。

I do not know how many of the problems you have solved so far, but having a fast primality test at your disposal will be of great value for a lot of the problems. 我不知道你到目前为止解决了多少问题,但是你可以使用快速素数测试对很多问题都有很大的价值。

You can first divide your n only by your primes_under_100 . 您可以先用primes_under_100除以n

Also, precompute more primes. 此外,预先计算更多的素数。

Also, you're actually store your range() result in memory - use irange() instead and use this memory for running Sieve of Eratosthenes algorithm . 此外,您实际上将range()结果存储在内存中 - 使用irange()代替并使用此内存运行Sieve of Eratosthenes算法

Well, I have a follow-up to my comment under (very good) Peter Van Der Heijden's answer about there being nothing good for really large primes (numbers in general) in the "popular" Python libraries. 好吧,我对(非常好)Peter Van Der Heijden的回答说明了我对“流行的”Python库中对于非常大的素数(一般数字)没什么好处的回答。 Turns out I was wrong - there is one in sympy (great library for symbolic algebra, among others): 事实证明我错了 - 有一个人sympy (伟大的符号代数库,以及其他):

https://docs.sympy.org/latest/modules/ntheory.html#sympy.ntheory.primetest.isprime https://docs.sympy.org/latest/modules/ntheory.html#sympy.ntheory.primetest.isprime

Of course, it may yield false positives above 10**16 , but this is already much better than anything else I could get doing nothing (except maybe pip install sympy ;) ) 当然,它可能会产生10**16以上的误报,但这已经比我无能为力的任何事情要好得多(除了pip install sympy ;))

def isprime(num):
if (num==3)or(num==2):
    return(True)
elif (num%2 == 0)or(num%5 == 0):
    return (False)
elif ((((num+1)%6 ==0) or ((num-1)%6 ==0)) and (num>1)):
    return (True)
else:
    return (False)

I think this code is the fastest .. 我认为这段代码是最快的..

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM