My current algorithm to check the primality of numbers in python is way to slow for numbers between 10 million and 1 billion. I want it to be improved knowing that I will never get numbers bigger than 1 billion.
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. 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.
I’m currently using the standard trial division tuned with 6k±1. Is there anything better than this? Do I already need to get the Rabin-Miller method for numbers that are this large.
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.
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!
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. 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). 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). 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.