A counter example for Polya's conjecture - python

Polya's conjecture is a mathematical conjecture that suppose that the sum of the first (-1)^(Omega(n)) where Omega(n) is the number of prime divisors of n with multiplicity, is always negative or zero.
A counter example is 906316571, was found fifty years ago. I wonder how could they found it because it takes a massive amount of time, I tried to optimize my python algorithm but it still takes a massive time, Can you help me optimize it ?
Here's my code (I used memoization)
>>> class Memoize:
def __init__(self, f):
self.f = f
self.memo = {}
def __call__(self, *args):
if not args in self.memo:
self.memo[args] = self.f(*args)
return self.memo[args]
>>> def sieve(m):
n=m+1;
s=[];
for i in range(2,n):
s.append(i);
k=0;
while k<len(s):
for i in range(2,int(n/s[k])+1):
x=i*s[k];
if s.count(x)==1:
s.remove(x);
k=k+1;
return s;
>>> s=sieve(100000);
>>> def omega(n):
k=0;
if n==1:
return 0;
else :
while k<len(s) and n%s[k]!=0 :
k=k+1;
if k<len(s):
return omega(int(n/s[k]))+1;
else :
return 1;
>>> omega=Memoize(omega)
>>> def polya(n):
h=omega(n);
if n==1:
return 0;
else :
if omega(n)%2==0:
return polya(n-1)+1;
else :
return polya(n-1)-1;
>>> polya=Memoize(polya);
>>> while polya(k)<=0 :
k=k+1;

As chepner told you, the original year 1958 proof was not done with brute force. Neither did it reveal the smallest number to break the rule, it was only found in 1980. I have not studied the case at all, but the 1980 proof may be have been done with a computer. It is more a question of the amount of RAM available, not a question of processing speed as such.
However, with modern computers it should not be overtly difficult to approach the problem with brute force. Python is not the best alternative here, but still the numbers can be found in a reasonable time.
import numpy as np
import time
max_number = 1000000000
# array for results
arr = np.zeros(max_number, dtype='int8')
# starting time
t0 = time.time()
# some tracking for the time spent
time_spent = []
# go through all possible numbers up to the larges possible factor
for p in range(2, int(np.sqrt(max_number))):
# if the number of factors for the number > 0, it is not a prime, jump to the next
if arr[p] > 0:
continue
# if we have a prime, we will have to go through all its powers < max_number
n = p
while n < max_number:
# increment the counter at n, 2n, 3n, ...
arr[n::n] += 1
# take the next power
n = n * p
# track the time spent
print "Time spent calculating the table of number of factors: {0} s".format(time.time()-t0)
# now we have the big primes left, but their powers are not needed any more
# they need to be taken into account up to max_number / 2
j = 0
for p in range(p + 1, (max_number + 1) / 2):
if arr[p] > 0:
continue
arr[p::p] += 1
if j % 10000 == 0:
print "{0} at {1} s".format(p, time.time()-t0)
j += 1
print "Primes up to {0} done at {1} s".format(p, time.time()-t0)
# now we have only big primes with no multiples left, they will be all 1
arr[arr == 0] = 1
print "Factor table done at {0} s".format(time.time() - t0)
# calculate the odd/even balance, note that 0 is not included and 1 has 0 factors
cumulative = np.cumsum(1 - 2 * (arr[1:] & 1), dtype='int32')
print "Total time {0} s".format(time.time()-t0)
This is not the fastest or the most optimized function, the mathematics behind this should be quite obvious. In my machine (i7) running on one core it takes approximately 2800 seconds to calculate the full table of number of prime factors up to 1 x 10^9. (But beware, do not try this without 64-bit python and at least 8 GB RAM. The cumulative sum table consumes 4 GB.)
To prove that the above function works at least quite well, here is a plot of the interesting area:
Due to some problems with the first numbers, the results given by the code above are slightly off. To get the official summatory Liouville lambda, use cumulative[n-1] + 2. For the number mentioned in the question (906 316 571) the result is cumulative[906316570] + 2 equalling to 829, which is the maximum value in the region.

Related

finding the lowest collatz sequence that gives more that 65 primes

I have a task where I need to find the lowest Collatz sequence that contains more than 65 prime numbers in Python.
For example, the Collatz sequence for 19 is:
19, 58, 29, 88, 44, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8,
4, 2, 1
This sequence contains 7 prime numbers.
I also need to use memoization so it doesn't have to run a "year" to find it. I found code for memoization of Collatz sequences, but I can't figure out how to get it to work when I need only the prime numbers.
Here is the Collatz memoization code that I found:
lookup = {}
def countTerms(n):
if n not in lookup:
if n == 1:
lookup[n] = 1
elif not n % 2:
lookup[n] = countTerms(n / 2)[0] + 1
else:
lookup[n] = countTerms(n*3 + 1)[0] + 1
return lookup[n], n
And here is my tester for prime:
def is_prime(a):
for i in xrange(2,a):
if a%i==0:
#print a, " is not a prime number"
return False
if a==1:
return False
else:
return True
Your existing code is incorrectly indented. I assume this task is a homework task, so I won't post a complete working solution, but I'll give you some helpful snippets.
First, here's a slightly more efficient primality tester. Rather than testing if all numbers less than a are factors of a, it just tests up to the square root of a.
def is_prime(a):
for i in xrange(2, int(1 + a ** 0.5)):
if a % i == 0:
return False
return True
Note that this function returns True for a = 1. That's ok, since you don't need to test 1: you can pre-load it into the lookup dict:
lookup = {1:0}
Your countTerms function needs to be modified slightly so that it only adds one to the lookup count when the current n is prime. In Python, False has a numeric value of 0 and True has a numeric value of 1. That's very handy here:
def count_prime_terms(n):
''' Count the number of primes terms in a Collatz sequence '''
if n not in lookup:
if n % 2:
next_n = n * 3 + 1
else:
next_n = n // 2
lookup[n] = count_prime_terms(next_n) + is_prime(n)
return lookup[n]
I've changed the function name to be more Pythonic.
FWIW, the first Collatz sequence containing 65 or more primes actually contains 67 primes. Its seed number is over 1.8 million, and the highest number that requires primality testing when checking all sequences up to that seed is 151629574372. At completion, the lookup dict contains 3920492 entries.
In response to James Mills's comments regarding recursion, I've written a non-recursive version, and to make it easy to see that the iterative and the recursive versions both produce the same results I'm posting a complete working program. I said above that I wasn't going to do that, but I figure that it should be ok to do so now, since spørreren has already written their program using the info I supplied in my original answer.
I fully agree that it's good to avoid recursion except in situations where it's appropriate to the problem domain (eg, tree traversal). Python discourages recursion - it cannot optimize tail-call recursion and it imposes a recursion depth limit (although that limit can be modified, if desired).
This Collatz sequence prime counting algorithm is naturally stated recursively, but it's not too hard to do iteratively - we just need a list to temporarily hold the sequence while the primality of all its members are being determined. True, this list takes up RAM, but it's (probably) much more efficient space-wise than the stack frame requirements that the recursive version needs.
The recursive version reaches a recursion depth of 343 when solving the problem in the OP. This is well within the default limit but it's still not good, and if you want to search for sequences containing much larger numbers of primes, you will hit that limit.
The iterative & recursive versions run at roughly the same speed (at least, they do so on my machine). To solve the problem stated in the OP they both take a little under 2 minutes. This is significantly faster than my original solution, mostly due to optimizations in primality testing.
The basic Collatz sequence generation step already needs to determine if a number is odd or even. Clearly, if we already know that a number is even then there's no need to test if it's a prime. :) And we can also eliminate tests for even factors in the is_prime function. We can handle the fact that 2 is prime by simply loading the result for 2 into the lookup cache.
On a related note, when searching for the first sequence containing a given number of primes we don't need to test any of the sequences that start at an even number. Even numbers (apart from 2) don't increase the prime count of a sequence, and since the first odd number in such a sequence will be lower than our current number its results will already be in the lookup cache, assuming we start our search from 3. And if we don't start searching from 3 we just need to make sure our starting seed is low enough so that we don't accidentally miss the first sequence containing the desired number of primes. Adopting this strategy not only reduces the time needed, it also reduces the number of entries in the lookup` cache.
#!/usr/bin/env python
''' Find the 1st Collatz sequence containing a given number of prime terms
From http://stackoverflow.com/q/29920691/4014959
Written by PM 2Ring 2015.04.29
[Seed == 1805311, prime count == 67]
'''
import sys
def is_prime(a):
''' Test if odd `a` >= 3 is prime '''
for i in xrange(3, int(1 + a ** 0.5), 2):
if not a % i:
return 0
return 1
#Track the highest number generated so far; use a list
# so we don't have to declare it as global...
hi = [2]
#Cache for sequence prime counts. The key is the sequence seed,
# the value is the number of primes in that sequence.
lookup = {1:0, 2:1}
def count_prime_terms_iterative(n):
''' Count the number of primes terms in a Collatz sequence
Iterative version '''
seq = []
while n not in lookup:
if n > hi[0]:
hi[0] = n
if n % 2:
seq.append((n, is_prime(n)))
n = n * 3 + 1
else:
seq.append((n, 0))
n = n // 2
count = lookup[n]
for n, isprime in reversed(seq):
count += isprime
lookup[n] = count
return count
def count_prime_terms_recursive(n):
''' Count the number of primes terms in a Collatz sequence
Recursive version '''
if n not in lookup:
if n > hi[0]:
hi[0] = n
if n % 2:
next_n = n * 3 + 1
isprime = is_prime(n)
else:
next_n = n // 2
isprime = 0
lookup[n] = count_prime_terms(next_n) + isprime
return lookup[n]
def find_seed(numprimes, start):
''' Find the seed of the 1st Collatz sequence containing
`numprimes` primes, starting from odd seed `start` '''
i = start
mcount = 0
print 'seed, prime count, highest term, dict size'
while mcount < numprimes:
count = count_prime_terms(i)
if count > mcount:
mcount = count
print i, count, hi[0], len(lookup)
i += 2
#count_prime_terms = count_prime_terms_recursive
count_prime_terms = count_prime_terms_iterative
def main():
if len(sys.argv) > 1:
numprimes = int(sys.argv[1])
else:
print 'Usage: %s numprimes [start]' % sys.argv[0]
exit()
start = int(sys.argv[2]) if len(sys.argv) > 2 else 3
#Round `start` up to the next odd number
if start % 2 == 0:
start += 1
find_seed(numprimes, start)
if __name__ == '__main__':
main()
When run with
$ ./CollatzPrimes.py 65
the output is
seed, prime count, highest term, dict size
3 3 16 8
7 6 52 18
19 7 160 35
27 25 9232 136
97 26 9232 230
171 28 9232 354
231 29 9232 459
487 30 39364 933
763 32 250504 1626
1071 36 250504 2197
4011 37 1276936 8009
6171 43 8153620 12297
10971 44 27114424 21969
17647 48 27114424 35232
47059 50 121012864 94058
99151 51 1570824736 198927
117511 52 2482111348 235686
202471 53 17202377752 405273
260847 55 17202377752 522704
481959 59 24648077896 966011
963919 61 56991483520 1929199
1564063 62 151629574372 3136009
1805311 67 151629574372 3619607
Let's begin with a function that determines if a number is prime; we will use the Miller-Rabin algorithm, which is faster than trial division for the size of numbers that we will be dealing with:
from random import randint
def isPrime(n, k=5): # miller-rabin
if n < 2: return False
for p in [2,3,5,7,11,13,17,19,23,29]:
if n % p == 0: return n == p
s, d = 0, n-1
while d % 2 == 0:
s, d = s+1, d/2
for i in range(k):
x = pow(randint(2, n-1), d, n)
if x == 1 or x == n-1: continue
for r in range(1, s):
x = (x * x) % n
if x == 1: return False
if x == n-1: break
else: return False
return True
Since we want to find the first number that satisfies the criteria, our strategy will be to start from 2 and work our way up, storing results as we go. We prime the cache (that's a bad pun, sorry) with the prime counts in the Collatz sequences from 0 to 2:
primeCount = [0,0,1]
Function pCount(n) counts the primes in the Collatz sequence for n. As soon as the current value of the sequence k drops below n, we look up the result in the cache. Until then, we test each odd number in the Collatz sequence for primality and increment the prime count p if appropriate. When we have the prime count for n, we add it to the cache and return it.
def pCount(n):
k, p = n, 0
while k > 0:
if k < n:
t = p + primeCount[k]
primeCount.append(t)
return t
elif k % 2 == 0:
k = k / 2
elif isPrime(k):
p = p + 1
k = 3*k + 1
else:
k = 3*k + 1
Now it's just a matter of computing the prime counts for each n, in order starting from 3, stopping when the prime count exceeds 65:
n = 3
t = pCount(n)
while t < 65:
n = n + 1
t = pCount(n)
That doesn't take long, less than a minute on my computer. Here's the result:
print n
There are 67 primes in the result. If you want to see them, here is a simple function that prints the Collatz sequence for a given n:
def collatz(n):
cs = []
while n != 1:
cs.append(n)
n = 3*n+1 if n&1 else n//2
cs.append(1)
return cs
And here's the list of primes:
filter(isPrime,collatz(n))
What a fun problem of recreational mathematics!
EDIT: Since people asked about the Miller-Rabin primality tester, let me show this simple primality tester based on a 2,3,5-wheel; it does trial division by 2, 3 and 5 and by numbers that aren't multiples of 2, 3, or 5, which includes some composites, so it's a little bit less efficient that trial division by primes, but there is no need to pre-compute and store the primes, so it's much easier to use.
def isPrime(n): # 2,3,5-wheel
if n < 2: return False
wheel = [1,2,2,4,2,4,2,4,6,2,6]
w, next = 2, 0
while w * w <= n:
if n % w == 0: return False
w = w + wheel[next]
next = next + 1
if next > 10: next = 3
return True
Saying filter(isPrime,range(1000000)) identifies the 78498 primes less than a million in just a few seconds. You might want to compare timings for this primality tester compared to the Miller-Rabin tester and determine where the crossover point is in terms of runtime efficiency; I didn't do any formal timings, but it seems to solve the 65-collatz-prime problem in about the same time as the Miller-Rabin teseter. Or you might want to combine trial division with a 2,3,5-wheel up to some limit, say 1000 or 10000 or 25000, then run Miller-Rabin on the survivors; that quickly eliminates most composites, so it can run very quickly.

Project Euler #10 (Python)

Why is my algorithm for finding the sum of all prime numbers below 2 million so slow?
I'm a fairly beginner programmer and this is what I came up with for finding the solution:
import time
sum = 2
start = time.time()
for number in range(3, 2000000):
prime = True
for x in range(2, number):
if number % x == 0:
prime = False
if prime:
sum += number
print "Sum =", sum
end = time.time() - start
print "Runtime =", end
Can someone please help me out?
Thanks!
Your algorithm uses trial division, which is very slow. A better algorithm uses the Sieve of Eratosthenes:
def sumPrimes(n):
sum, sieve = 0, [True] * n
for p in range(2, n):
if sieve[p]:
sum += p
for i in range(p*p, n, p):
sieve[i] = False
return sum
print sumPrimes(2000000)
That should run in less than a second. If you're interested in programming with prime numbers, I modestly recommend this essay at my blog.
There are many optimisations that you could do (and should do since you will need prime generation for many of the problems in project Euler, so having a fast implementation simplifies things later on).
Take a look at the sieve of Atkin (and related sieves) (http://en.wikipedia.org/wiki/Sieve_of_Atkin) to get an understanding of how prime generation can be speeded up over brute force (algorithmically that is).
Then take a look at the awesome answer to this S.O.-post (Fastest way to list all primes below N) that clocks a number of prime generation algorithms/implementations.
Nobody pointed this out, but using range in Python 2.x is very slow. Use xrange instaed, in this case this should give you a huge performance advantage.
See this question.
Also, you don't have to loop until the number you check, checking until round(sqrt(n)) + 1 is sufficient. (If the number greater than its square divides it, there's a number smaller than the square that you must have already noticed.)
You need to use prime sieve check out eratostheneses sieve and try to implement it in code.
Trial division is very inefficient for finding primes because it has complexity n square, the running time grows very fast. This task is meant to teach you how to find something better.
First off, you're looping over too many numbers. You don't need to check if EVERY number less than a given number is a divisor to check if a number is prime (I'll let you figure out why this is yourself). You are running hundreds of billions of loops, where hundreds of millions will do.
Something like this works faster, but is by no means optimal:
value=2
for i in range(3, 2000000):
prime=True
if i%2 != 0:
for j in range(3, int(round(sqrt(i)+1)),2):
if i % j==0:
prime=False
else:
prime=False
if prime==True:
value+=i
print value
First of all, I think you can split your code by defining a function. However, there is a drawback of using a regular function in this case because every time a normal function return a value, the next call to the function will execute the complete code inside the function again. Since you are iterating 2 million times, it would be better to:
Have a function that gives you the next prime number and provisionally returns the control to the caller. Such functions are known as GENERATORS.
To define a generator function just use the yield command instead of return.
When you use generators , it is like knowing that the function will be called again and when it happens the execution inside the function continues right after the yield instruction instead of going over the whole function again.
The advantage of this approach is that on the long run of an iterator you avoid the consumption all of the system's memory.
I recommend you to have a look at this article about generators in python. It provides a more extensive explanation for this example.
The solution would be something like this:
import math
# Check if a number is prime
def is_prime(number):
if number > 1:
if number == 2:
return True
if number % 2 == 0:
return False
for current in range(3, int(math.sqrt(number) + 1), 2):
if number % current == 0:
return False
return True
return False
# Get the next after a given number
def get_primes(number):
while True:
if is_prime(number):
yield number
# Next call to the function will continue here!
number += 1
# Get the sum of all prime numbers under a number
def sum_primes_under(limit):
total = 2
for next_prime in get_primes(3):
if next_prime < limit:
total += next_prime
else:
print(total)
return
# Call the function
sum_primes_under(2000000)
This question gives output quite very fast when you use sieve of eratosthenes Link to it. You can make it even more faster with a little modification like iterating the whole 2 million numbers just half times by considering only the odd numbers. This way you can save lots of time.
n = 2000000
ar = [False for x in range(n)]
sum = 2
def mul(a):
i = 2;p = i*a
while (p < n):
ar[p] = 1
++i
p = i*a
while (x < n):
if(ar[x] == 0):
sum += x;mul(x)
x += 2
print (sum)
Here you can see the same algorithm in c++:-
#include<bits/stdc++.h>
using namespace std;
const int n = 2000000;
bool ar[n];
void mul(int a)
{
int i = 2;int p = i*a;
while(p < n)
{
ar[p] = 1;
++i;p = i*a;
}
}
long long sieve()
{
long long sum = 2;
for(int i = 3;i < n;i += 2)
{
if(ar[i] == 0)
sum += i,mul(i);
}
return sum;
}
int main()
{
cout<<sieve();
return 0;
}
C++ works around 10 times faster than python anyways and for this algorithm too.
sum = 2
def isPrime(n):
if n % 2 == 0: return False
for i in range(3, int(n**0.5)+1, 2):
if n % i == 0: return False
return True
if __name__ == "__main__":
n = 1
while n < 2000000:
n += 2
if isPrime(n):sum += n
print sum
import time
start = time.time()
def is_prime(num):
prime = True
for i in range(2,int(num**0.5)+1):
if num % i == 0:
prime = False
break
return prime
sum_prime = 0
for i in range(2,2000000):
if is_prime(i):
sum_prime += i
print("sum: ",sum_prime)
elapsed = (time.time() - start)
print("This code took: " + str(elapsed) + " seconds")

What's wrong with my python solution to Project Euler #12?

Possible Spoiler Warning
I've spent ages trying to improve this algorithm and work out what's going wrong, but I can't seem to work out why the outputted answer is incorrect.
I'm trying to solve Project Euler #12, to get the lowest triangular number to have over 500 divisors, but it says my answer is incorrect.
Here is my Python code:
import time
# function to get the number of divisors
def div(n):
d=2
for i in range(2,int(n**.5)+2):
if (n % i) == 0:
d += 1
return d
start = time.time()
w = True
n=m=1
while w:
n += 1
s = (n*(n+1))/2 # nth triangle number
r = div(s)
if r > m:
m = r
print s,"has",r,"divisors"
if r > 500:
w = False
print "Solved in",((time.time()-start)*1000),"milliseconds"
And the output for that code is this (in 66 seconds):
3 has 2 divisors
6 has 4 divisors
36 has 6 divisors
120 has 9 divisors
...
76576500 has 289 divisors
103672800 has 325 divisors
236215980 has 385 divisors
842161320 has 513 divisors
Solved in 65505.5799484 milliseconds
However, if I input 842161320 into the Project Euler problem, it says it's incorrect.
What am I doing wrong?
I see two bugs:
Your div function is broken: div(24) == 5, while it should be 8
Your 1st triangular number would be 3, although it should be 1
You could implement a working div like this:
import math
def divisors(n):
return sum(1 for x in range(1, n+1) if n % x == 0)
Also, that code is inefficient as hell, some suggestions to improve it are:
Instead of calculating the nth triangular number using your formula, use a rolling sum:
import itertools
s = 0
for i in itertools.count(1):
s += i
if div(s) > 500:
print s
break
Also, Use prime factors to calculate the number of divisors. You can create a prime factor cache for maximum performance.
You are undercounting the total number of divisors. 36, for example, has 9 divisors: 1,2,3,4,6,9,12,18,36. It's true the algorithm only needs to test numbers smaller than sqrt(n) to find all divisors, but you still need to include the implied "large" divisors in your count.
Solved
With the help of Niklas, and changing my div method, I've got the answer. Also, it's now only takes 8% of the time my previous algorithm took.
The algorithm now looks like this:
import time
import itertools
def div(n):
d=0
for i in range(1,int(n**.5)+1):
if (n % i) == 0:
d += 1
return 2*d
start = time.time()
s = m = 0
for i in itertools.count(1):
s += i
r = div(s)
if r > m:
m = r
print s,"has",r,"factors"
if div(s) > 500:
break
print "Solved in",((time.time()-start)*1000),"milliseconds"

Project Euler 5 in Python - How can I optimize my solution?

I've recently been working on Project Euler problems in Python. I am fairly new to Python, and still somewhat new as a programmer.
In any case, I've ran into a speed-related issue coding a solution for problem #5. The problem is,
"2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder. What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?"
I've checked around some, and I haven't been able to find anything on this problem pertaining to Python specifically. There were some completed scripts, but I want to avoid looking at other's code in full, if possible, instead wanting to improve my own.
The code I have written runs successfully for the example of 2520 and the range 1 to 10, and should be directly modifiable to work with the question. However, upon running it, I do not get an answer. Presumably, it is a very high number, and the code is not fast enough. Printing the current number being checked seems to support this, reaching several million without getting an answer.
The code, in it's current implementation is as follows:
rangemax = 20
def div_check(n):
for i in xrange(11,rangemax+1):
if n % i == 0:
continue
else:
return False
return True
if __name__ == '__main__':
num = 2
while not div_check(num):
print num
num += 2
print num
I have already made a couple changes which I think should help the speed. For one, for a number to be divisible by all numbers 1 to 20, it must be even, as only even numbers are divisible by 2. Hence, I can increment by 2 instead of 1. Also, although I didn't think of it myself, I found someone point out that a number divisible by 11 to 20 is divisible by 1 to 10. (Haven't checked that one, but it seems reasonable)
The code still, however is not fast enough. What optimisations, either programmatic, or mathematics, can I make to make this code run faster?
Thanks in advance to any who can help.
Taking the advice of Michael Mior and poke, I wrote a solution. I tried to use a few tricks to make it fast.
Since we need a relatively short list of numbers tested, then we can pre-build the list of numbers rather than repeatedly calling xrange() or range().
Also, while it would work to just put the numbers [1, 2, 3, ..., 20] in the list, we can think a little bit, and pull numbers out:
Just take the 1 out. Every integer is evenly divisible by 1.
If we leave the 20 in, there is no need to leave the 2 in. Any integer evenly divisible by 20 is evenly divisible by 2 (but the reverse might not be true). So we leave the 20 and take out the 2, the 4, and the 5. Leave the 19, as it's prime. Leave the 18, but now we can take out the 3 and the 6. If you repeat this process, you wind up with a much shorter list of numbers to try.
We start at 20 and step numbers by 20, as Michael Mior suggested. We use a generator expression inside of all(), as poke suggested.
Instead of a while loop, I used a for loop with xrange(); I think this is slightly faster.
The result:
check_list = [11, 13, 14, 16, 17, 18, 19, 20]
def find_solution(step):
for num in xrange(step, 999999999, step):
if all(num % n == 0 for n in check_list):
return num
return None
if __name__ == '__main__':
solution = find_solution(20)
if solution is None:
print "No answer found"
else:
print "found an answer:", solution
On my computer, this finds an answer in under nine seconds.
EDIT:
And, if we take advice from David Zaslavsky, we realize we can start the loop at 2520, and step by 2520. If I do that, then on my computer I get the correct answer in about a tenth of a second.
I made find_solution() take an argument. Try calling find_solution(2520).
My first answer sped up the original calculation from the question.
Here's another answer that solves it a different way: just find all the prime factors of each number, then multiply them together to go straight to the answer. In other words, this automates the process recommended by poke in a comment.
It finishes in a fraction of a second. I don't think there is a faster way to do this.
I did a Google search on "find prime factors Python" and found this:
http://www.stealthcopter.com/blog/2009/11/python-factors-of-a-number/
From that I found a link to factor.py (written by Mike Hansen) with some useful functions:
https://gist.github.com/weakish/986782#file-factor-py
His functions didn't do quite what I wanted, so I wrote a new one but used his pull_prime_factors() to do the hard work. The result was find_prime_factors() which returns a list of tuples: a prime number, and a count. For example, find_prime_factors(400) returns [(2,4), (5,2)] because the prime factors of 400 are: (2*2*2*2)*(5*5)
Then I use a simple defaultdict() to keep track of how many we have seen so far of each prime factor.
Finally, a loop multiplies everything together.
from collections import defaultdict
from factor import pull_off_factors
pf = defaultdict(int)
_primes = [2,3,5,7,11,13,17,19,23,29]
def find_prime_factors(n):
lst = []
for p in _primes:
n = pull_off_factors(n, p, lst)
return lst
def find_solution(low, high):
for num in xrange(low, high+1):
lst = find_prime_factors(num)
for n, count in lst:
pf[n] = max(pf[n], count)
print "prime factors:", pf
solution = 1
for n, count in pf.items():
solution *= n**count
return solution
if __name__ == '__main__':
solution = find_solution(1, 20)
print "answer:", solution
EDIT: Oh wow, I just took a look at #J.F. Sebastian's answer to a related question. His answer does essentially the same thing as the above code, only far more simply and elegantly. And it is in fact faster than the above code.
Least common multiple for 3 or more numbers
I'll leave the above up, because I think the functions might have other uses in Project Euler. But here's the J.F. Sebastian solution:
def gcd(a, b):
"""Return greatest common divisor using Euclid's Algorithm."""
while b:
a, b = b, a % b
return a
def lcm(a, b):
"""Return lowest common multiple."""
return a * b // gcd(a, b)
def lcmm(*args):
"""Return lcm of args."""
return reduce(lcm, args)
def lcm_seq(seq):
"""Return lcm of sequence."""
return reduce(lcm, seq)
solution = lcm_seq(xrange(1,21))
print "lcm_seq():", solution
I added lcm_seq() but you could also call:
lcmm(*range(1, 21))
Since your answer must be divisible by 20, you can start at 20 and increment by 20 instead of by two. In general, you can start at rangemax and increment by rangemax. This reduces the number of times div_check is called by an order of magnitude.
Break down the number as a prime factorization.
All primes less than 20 are:
2,3,5,7,11,13,17,19
So the bare minimum number that can be divided by these numbers is:
2*3*5*7*11*13*17*19
Composites:
4,6,8,9,10,12,14,15,16,18,20 = 2^2, 2*3, 2^3, 3^2, 2*5, 2^2*3, 2*7, 3*5, 2*3^2, 2^2*5
Starting from the left to see which factors needed:
2^3 to build 4, 8, and 16
3 to build 9
Prime factorization: 2^4 * 3^2 * 5 * 7 * 11 * 13 * 17 * 19 = 232,792,560
I got the solution in 0.066 milliseconds (only 74 spins through a loop) using the following procedure:
Start with smallest multiple for 1, which = 1. Then find the smallest multiple for the next_number_up. Do this by adding the previous smallest multiple to itself (smallest_multiple = smallest_multiple + prev_prod) until next_number_up % smallest_multiple == 0. At this point smallest_multiple is the correct smallest multiple for next_number_up. Then increment next_number_up and repeat until you reach the desired smallest_multiple (in this case 20 times). I believe this finds the solution in roughly n*log(n) time (though, given the way numbers seem to work, it seems to complete much faster than that usually).
For example:
1 is the smallest multiple for 1
Find smallest multiple for 2
Check if previous smallest multiple works 1/2 = .5, so no
previous smallest multiple + previous smallest multiple == 2.
Check if 2 is divisible by 2 - yes, so 2 is the smallest multiple for 2
Find smallest multiple for 3
Check if previous smallest multiple works 2/3 = .667, so no
previous smallest multiple + previous smallest multiple == 4
Check if 4 is divisible by 3 - no
4 + previous smallest multiple == 6
Check if 6 is divisible by 3 - yes, so 6 is the smallest multiple for 3
Find smallest multiple for 4
Check if previous smallest multiple works 6/4 = 1.5, so no
previous smallest multiple + previous smallest multiple == 12
Check if 12 is divisble by 4 - yes, so 12 is the smallest multiple for 4
repeat until 20..
Below is code in ruby implementing this approach:
def smallestMultiple(top)
prod = 1
counter = 0
top.times do
counter += 1
prevprod = prod
while prod % counter != 0
prod = prod + prevprod
end
end
return prod
end
List comprehensions are faster than for loops.
Do something like this to check a number:
def get_divs(n):
divs = [x for x in range(1,20) if n % x == 0]
return divs
You can then check the length of the divs array to see if all the numbers are present.
Two different types of solutions have been posted here. One type uses gcd calculations; the other uses prime factorization. I'll propose a third type, which is based on the prime factorization approach, but is likely to be much faster than prime factorization itself. It relies on a few simple observations about prime powers -- prime numbers raised to some integral exponent. In short, it turns out that the least common multiple of all numbers below some number n is equal to the product of all maximal prime powers below n.
To prove this, we begin by thinking about the properties that x, the least common multiple of all numbers below n, must have, and expressing them in terms of prime powers.
x must be a multiple of all prime powers below n. This is obvious; say n = 20. 2, 2 * 2, 2 * 2 * 2, and 2 * 2 * 2 * 2 are all below 20, so they all must divide x. Likewise, 3 and 3 * 3 are both below n and so both must divide x.
If some number a is a multiple of the prime power p ** e, and p ** e is the maximal power of p below n, then a is also a multiple of all smaller prime powers of p. This is also quite obvious; if a == p * p * p, then a == (p * p) * p.
By the unique factorization theorem, any number m can be expressed as a multiple of prime powers less than m. If m is less than n, then m can be expressed as a multiple of prime powers less than n.
Taken together, the second two observations show that any number x that is a multiple of all maximal prime powers below n must be a common multiple of all numbers below n. By (2), if x is a multiple of all maximal prime powers below n, it is also a multiple of all prime powers below n. So by (3), it is also a multiple of all other numbers below n, since they can all be expressed as multiples of prime powers below n.
Finally, given (1), we can prove that x is also the least common multiple of all numbers below n, because any number less than x could not be a multiple of all maximal prime powers below n, and so could not satisfy (1).
The upshot of all this is that we don't need to factorize anything. We can just generate primes less than n!
Given a nicely optimized sieve of eratosthenes, one can do that very quickly for n below one million. Then all you have to do is find the maximal prime power below n for each prime, and multiply them together.
prime_powers = [get_max_prime_power(p, n) for p in sieve(n)]
result = reduce(operator.mul, prime_powers)
I'll leave writing get_max_prime_power as an exercise. A fast version, combined with the above, can generate the lcm of all numbers below 200000 in 3 seconds on my machine.
The result is a 86871-digit number!
This solution ran pretty quickly for me (imports numpy).
t0 = time.time()
import numpy
ints = numpy.array(range(1,21))
primes = [2,3,5,7,11,13,17,19] # under 20
facts = []
for p in primes:
counter = 0
nums = ints
while any(nums % p == 0):
nums = nums / float(p)
counter += 1
facts.append(counter)
facts = numpy.array(facts)
mults = primes**facts
ans = 1
for m in mults:
ans = m * ans
t1 =time.time()
perf = t1 - t0
print "Problem 5\nAnswer:",ans, "runtime:", perf, "seconds"
"""Problem 5
Answer: 232792560 runtime: 0.00505399703979 seconds"""
Here i have also done using prime factorization way.
#!/usr/bin/env python
import math
def is_prime(num):
if num > 1:
if num == 2:
return True
if num%2 == 0:
return False
for i in range(3, int(math.sqrt(num))+1, 2):
if num%i == 0:
return False
return True
return False
def lcm(number):
prime = []
lcm_value = 1
for i in range(2,number+1):
if is_prime(i):
prime.append(i)
final_value = []
for i in prime:
x = 1
while i**x < number:
x = x + 1
final_value.append(i**(x-1))
for j in final_value:
lcm_value = j * lcm_value
return lcm_value
if __name__ == '__main__':
print lcm(20)
After checking how much time it has taken, it was not bad at all.
root#l-g6z6152:~/learn/project_euler# time python lcm.py
232792560
real 0m0.019s
user 0m0.008s
sys 0m0.004s
I wrote a solution to euler5 that:
Is orders of magnitude faster than most of the solutions here when n=20 (though not all respondents report their time) because it uses no imports (other than to measure time for this answer) and only basic data structures in python.
Scales much better than most other solutions. It will give the answer for n=20 in 6e-05 seconds, or for n=100 in 1 millisec, faster than most of the responses for n=20 listed here.
import time
a=time.clock() # set timer
j=1
factorlist=[]
mydict={}
# change second number to desired number +1 if the question were changed.
for i in range(2,21,1):
numberfactors=[]
num=i
j=2
# build a list of the prime factors
for j in range(j,num+1,1):
counter=0
if i%j==0:
while i%j==0:
counter+=1
numberfactors.append(j)
i=i/j
# add a list of factors to a dictionary, with each prime factor as a key
if j not in mydict:
mydict[j] = counter
# now, if a factor is already present n times, including n times the factor
# won't increase the LCM. So replace the dictionary key with the max number of
# unique factors if and only if the number of times it appears is greater than
# the number of times it has already appeared.
# for example, the prime factors of 8 are 2,2, and 2. This would be replaced
# in the dictionary once 16 were found (prime factors 2,2,2, and 2).
elif mydict[j] < counter:
mydict[j]=counter
total=1
for key, value in mydict.iteritems():
key=int(key)
value=int(value)
total=total*(key**value)
b=time.clock()
elapsed_time=b-a
print total, "calculated in", elapsed_time, "seconds"
returns:
232792560 calculated in 6e-05 seconds
# does not rely on heuristics unknown to all users, for instance the idea that
# we only need to include numbers above 10, etc.
# For all numbers evenly divisible by 1 through 100:
69720375229712477164533808935312303556800 calculated in 0.001335 seconds
Here is program in C language. Cheers
#include <stdio.h>
#include <stdlib.h>
//2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
//What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
bez_ost(int q)
{
register br=0;
for( register i=1;i<=20;i++)
if(q%i==0)
br++;
if(br==20)
return 1;
return 0;
}
int main()
{
register j=20;
register ind=0;
while(ind!=1)
{
j++;
if(bez_ost(j))
break;
}
fprintf(stdout,"\nSmallest positive number that is evenlu divisible by all of the numbers from 1 to 20 is: %d\n\a",j);
system("Pause");
}
I've had the same problem. The algorithm seems to be quite slow, but it does work nonetheless.
result = list()
xyz = [x for x in range(11, 21)]
number = [2520]
count = 0
while len(result) == 0:
for n in number:
print n
for x in xyz:
if n % x == 0:
count += 1
elif n % x != 0:
count = 0
break
if count == 10:
result.append(number[0])
elif count != 10:
number[0] += 1
print result
This was the algorithm I made.
How about this? The required number is, after all, the LCM of the given numbers.
def lcm(a,b):
lcm1 = 0
if a == b:
lcm1 = a
else:
if a > b:
greater = a
else:
greater = b
while True:
if greater % a == 0 and greater % b == 0:
lcm1 = greater
break
greater += 1
return lcm1
import time
start_time = time.time()
list_numbers = list(range(2,21))
lcm1 = lcm(list_numbers[0],list_numbers[1])
for i in range(2,len(list_numbers)):
lcm1 = lcm(lcm1,list_numbers[i])
print(lcm1)
print('%0.5f'%(time.time()-start_time))
This code took a full 45 s to get the answer to the actual question! Hope it helps.
import time
primes = [11,13,17,19]
composites = [12,14,15,16,18,20]
def evenlyDivisible(target):
evenly = True
for n in composites:
if target % n > 0:
evenly = False
break
return evenly
step = 1
for p in primes:
step *= p
end = False
number = 0
t1 = time.time()
while not end:
number += step
if evenlyDivisible(number):
end = True
print("Smallest positive evenly divisible number is",number)
t2 = time.time()
print("Time taken =",t2-t1)
Executed in 0.06 seconds
Here is my Python solution, it has 12 iteration so compiled quite fast:
smallest_num = 1
for i in range (1,21):
if smallest_num % i > 0: # If the number is not divisible by i
for k in range (1,21):
if (smallest_num * k) % i == 0: # Find the smallest number divisible by i
smallest_num = smallest_num * k
break
print (smallest_num)
Here's an observation on this problem. Ultimately, it takes 48 iterations to find the solution.
Any number that is divisible by all of the numbers from 1..20 must be divisible by the product of the primes in that range, namely 2, 3, 5, 7, 11, 13, 17, and 19. It cannot be smaller than the product of these primes, so let's use that number, 232,792,560, as the increment, rather than 20, or 2,520, or some other number.
As it turns out, 48 * 232,792,560 is divisible by all numbers 1..20. By the way, the product of all of the non-primes between 1..20 is 66. I haven't quite figured out the relationship between 48 and 66 in this context.
up = int(input('Upper limit: '))
number = list(range(1, up + 1))
n = 1
for i in range(1, up):
n = n * number[i]
for j in range(i):
if number[i] % number[j] == 0:
n = n / number[j]
number[i] = number[i] / number[j]
print(n)
How I can reduce the complexity of this
num = 1
found = False
while not found:
count =0
for i in range(1, 21):
if num %i == 0:
count+=1
if count ==10:
print(num)
found = True
num+=1
Here is the code in C++ to find the solution for this question.
What we have to do is to run a loop from 1 until we got that number so just iterate through the loop and once the number get evenly divisble(remainder 0) flag value dont get change and flag remains 1 and we got that number and break through outer loop and print the answer
#include <bits/stdc++.h>
using namespace std;
int main()
{
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int i,j,flag=1;
for(i=1;;i++) //iterate until we got the number
{
flag=1;
for(j=2;j<=20;j++) //check form 1 to 20 for that number
{
if(i%j!=0) //if the number is not evenly divisible we break loop and
{
flag=0;break; // initilize flag as 0 i.e. that number is not what we want
}
}
if(flag==1) //if any number we got that is evenly divisible i.e. flag value doesnt change we got that number we break through the loop and print the answer
break;
} // after ending of the loop as we jump to next number make flag also 1 again so that again inner loop conditions apply on it
cout<<i;
return 0;
}
A typescript variant that seems to be relatively quick, leveraging recursion and known facts.
describe(`2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?`,
() => {
it("prooves the example: 10", () => smallestWithoutRemainder(10).should.be.equal(2520));
it("prooves 1", () => smallestWithoutRemainder(1).should.be.equal(1));
it("prooves 2", () => smallestWithoutRemainder(2).should.be.equal(2));
it("prooves 3", () => smallestWithoutRemainder(3).should.be.equal(6));
it("prooves 4", () => smallestWithoutRemainder(4).should.be.equal(12));
it("prooves 5", () => smallestWithoutRemainder(5).should.be.equal(60));
it("prooves 6", () => smallestWithoutRemainder(6).should.be.equal(60));
it("prooves 7", () => smallestWithoutRemainder(7).should.be.equal(420));
it("prooves 8", () => smallestWithoutRemainder(8).should.be.equal(840));
it("prooves 9", () => smallestWithoutRemainder(9).should.be.equal(2520));
it("prooves 12", () => smallestWithoutRemainder(12).should.be.equal(27720));
it("prooves 20", () => smallestWithoutRemainder(20).should.be.equal(232792560));
it("prooves 30", () => smallestWithoutRemainder(30).should.be.equal(2329089562800));
it("prooves 40", () => smallestWithoutRemainder(40).should.be.equal(5342931457063200));
});
let smallestWithoutRemainder = (end: number, interval?: number) => {
// What do we know?
// - at 10, the answer is 2520
// - can't be smaller than the lower multiple of 10
// - must be an interval of the lower multiple of 10
// so:
// - the interval and the start should at least be divisable by 'end'
// - we can recurse and build on the results before it.
if (!interval) interval = end;
let count = Math.floor(end / 10);
if (count == 1) interval = 2520;
else if (count > 1) interval = smallestWithoutRemainder((count - 1) * 10, interval);
for (let i = interval; true; i += interval) {
let failed = false;
for (let j = end; j > 1; j--) {
if (i % j != 0) {
failed = true;
break;
}
}
if (!failed) return i;
}
}
I think this the answer:
primes = [11, 13, 17, 19]
result = 2520
for i in primes:
result *= i
print (result * 2)

How can I get this Python code to run more quickly? [Project Euler Problem #7]

I'm trying to complete this Project Euler challenge:
By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can
see that the 6th prime is 13.
What is the 10 001st prime number?
My code seem to be right because it works with small numbers, e.g 6th prime is 13.
How can i improve it so that the code will run much more quickly for larger numbers such as 10 001.
Code is below:
#Checks if a number is a prime
def is_prime(n):
count = 0
for i in range(2, n):
if n%i == 0:
return False
break
else:
count += 1
if count == n-2:
return True
#Finds the value for the given nth term
def term(n):
x = 0
count = 0
while count != n:
x += 1
if is_prime(x) == True:
count += 1
print x
term(10001)
UPDATE:
Thanks for your responses. I should have been more clear, I am not looking to speed up the interpreter or finding a faster interpreter, because i know my code isn't great, so i was looking for ways of make my code more efficient.
A few questions to ponder:
Do you really need to check the division until n-1? How earlier can you stop?
Apart from 2, do you really need to check the division by all the multiples of two ?
What about the multiples of 3? 5? Is there a way to extend this idea to all the multiples of previously tested primes?
The purpose of Project Euler is not really to think learn programming, but to think about algorithms. On problem #10, your algorithm will need to be even faster than on #7, etc. etc. So you need to come up with a better way to find prime numbers, not a faster way to run Python code. People solve these problems under the time limit with far slower computers that you're using now by thinking about the math.
On that note, maybe ask about your prime number algorithm on https://math.stackexchange.com/ if you really need help thinking about the problem.
A faster interpreter won't cut it. Even an implementation written in C or assembly language won't be fast enough (to be in the "about one second" timeframe of project Euler). To put it bluntly, your algorithm is pathetic. Some research and thinking will help you write an algorithm that runs faster in a dog-slow interpreter than your current algorithm implemented in native code (I won't name any specifics, partly because that's your job and partly because I can't tell offhand how much optimization will be needed).
Many of the Euler problems (including this one) are designed to have a solution that computes in acceptable time on pretty much any given hardware and compiler (well, not INTERCAL on a PDP-11 maybe).
You algorithm works, but it has quadratic complexity. Using a faster interpreter will give you a linear performance boost, but the quadratic complexity will dwarf it long before you calculate 10,000 primes. There are algorithms with much lower complexity; find them (or google them, no shame in that and you'll still learn a lot) and implement them.
Without discussing your algorithm, the PyPy interpreter can be ridiculously faster than the normal CPython one for tight numerical computation like this. You might want to try it out.
to check the prime number you dont have to run till n-1 or n/2....
To run it more faster,you can check only until square root of n
And this is the fastest algorithm I know
def isprime(number):
if number<=1:
return False
if number==2:
return True
if number%2==0:
return False
for i in range(3,int(sqrt(number))+1):
if number%i==0:
return False
return True
As most people have said, it's all about coming up with the correct algorithm. Have you considered looking at a
Sieve of Eratosthenes
import time
t=time.time()
def n_th_prime(n):
b=[]
b.append(2)
while len(b)<n :
for num in range(3,n*11,2):
if all(num%i!=0 for i in range(2,int((num)**0.5)+1)):
b.append(num)
print list(sorted(b))[n-1]
n_th_prime(10001)
print time.time()-t
prints
104743
0.569000005722 second
A pythonic Answer
import time
t=time.time()
def prime_bellow(n):
b=[]
num=2
j=0
b.append(2)
while len(b)-1<n:
if all(num%i!=0 for i in range(2,int((num)**0.5)+1)):
b.append(num)
num += 1
print b[n]
prime_bellow(10001)
print time.time()-t
Prints
104743
0.702000141144 second
import math
count = 0 <br/> def is_prime(n):
if n % 2 == 0 and n > 2:
return False
for i in range(3, int(math.sqrt(n)) + 1, 2):
if n % i == 0:
return False
return True
for i in range(2,2000000):
if is_prime(i):
count += 1
if count == 10001:
print i
break
I approached it a different way. We know that all multiples of 2 are not going to be prime (except 2) we also know that all non-prime numbers can be broken down to prime constituents.
i.e.
12 = 3 x 4 = 3 x 2 x 2
30 = 5 x 6 = 5 x 3 x 2
Therefore I iterated through a list of odd numbers, accumulating a list of primes, and only attempting to find the modulus of the odd numbers with primes in this list.
#First I create a helper method to determine if it's a prime that
#iterates through the list of primes I already have
def is_prime(number, list):
for prime in list:
if number % prime == 0:
return False
return True
EDIT: Originally I wrote this recursively, but I think the iterative case is much simpler
def find_10001st_iteratively():
number_of_primes = 0
current_number = 3
list_of_primes = [2]
while number_of_primes <= 10001:
if is_prime(current_number, list_of_primes):
list_of_primes.append(current_number)
number_of_primes += 1
current_number += 2
return current_number
A different quick Python solution:
import math
prime_number = 4 # Because 2 and 3 are already prime numbers
k = 3 # It is the 3rd try after 2 and 3 prime numbers
milestone = 10001
while k <= milestone:
divisible = 0
for i in range(2, int(math.sqrt(prime_number)) + 1):
remainder = prime_number % i
if remainder == 0: #Check if the number is evenly divisible (not prime) by i
divisible += 1
if divisible == 0:
k += 1
prime_number += 1
print(prime_number-1)
import time
t = time.time()
def is_prime(n): #check primes
prime = True
for i in range(2, int(n**0.5)+1):
if n % i == 0:
prime = False
break
return prime
def number_of_primes(n):
prime_list = []
counter = 0
num = 2
prime_list.append(2)
while counter != n:
if is_prime(num):
prime_list.append(num)
counter += 1
num += 1
return prime_list[n]
print(number_of_primes(10001))
print(time.time()-t)
104743
0.6159017086029053
based on the haskell code in the paper: The Genuine Sieve of Eratosthenes by Melissa E. O'Neill
from itertools import cycle, chain, tee, islice
wheel2357 = [2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,8,6,4,6,2,4,6,2,6,6,4,2,4,6,2,6,4,2,4,2,10,2,10]
def spin(wheel, n):
for x in wheel:
yield n
n = n + x
import heapq
def insertprime(p,xs,t):
heapq.heappush(t,(p*p,(p*v for v in xs)))
def adjust(t,x):
while True:
n, ns = t[0]
if n <= x:
n, ns = heapq.heappop(t)
heapq.heappush(t, (ns.next(), ns))
else:
break
def sieve(it):
t = []
x = it.next()
yield x
xs0, xs1 = tee(it)
insertprime(x,xs1,t)
it = xs0
while True:
x = it.next()
if t[0][0] <= x:
adjust(t,x)
continue
yield x
xs0, xs1 = tee(it)
insertprime(x,xs1,t)
it = xs0
primes = chain([2,3,5,7], sieve(spin(cycle(wheel2357), 11)))
from time import time
s = time()
print list(islice(primes, 10000, 10001))
e = time()
print "%.8f seconds" % (e-s)
prints:
[104743]
0.18839407 seconds
from itertools import islice
from heapq import heappush, heappop
wheel2357 = [2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,
4,8,6,4,6,2,4,6,2,6,6,4,2,4,6,2,6,4,2,4,2,10,2,10]
class spin(object):
__slots__ = ('wheel','o','n','m')
def __init__(self, wheel, n, o=0, m=1):
self.wheel = wheel
self.o = o
self.n = n
self.m = m
def __iter__(self):
return self
def next(self):
v = self.m*self.n
self.n += self.wheel[self.o]
self.o = (self.o + 1) % len(self.wheel)
return v
def copy(self):
return spin(self.wheel, self.n, self.o, self.m)
def times(self, x):
return spin(self.wheel, self.n, self.o, self.m*x)
def adjust(t,x):
while t[0][0] <= x:
n, ns = heappop(t)
heappush(t, (ns.next(), ns))
def sieve_primes():
for p in [2,3,5,7]:
yield p
it = spin(wheel2357, 11)
t = []
p = it.next()
yield p
heappush(t, (p*p, it.times(p)))
while True:
p = it.next()
if t[0][0] <= p:
adjust(t,p)
continue
yield p
heappush(t, (p*p, it.times(p)))
from time import time
s = time()
print list(islice(sieve_primes(), 10000, 10001))[-1]
e = time()
print "%.8f seconds" % (e-s)
prints:
104743
0.22022200 seconds
import time
from math import sqrt
wheel2357 = [2,4,2,4,6,2,6,4,2,4,6,6,2,6,4,2,6,4,6,8,4,2,4,2,4,8,6,4,6,2,4,6,2,6,6,4,2,4,6,2,6,4,2,4,2,10,2,10]
list_prime = [2,3,5,7]
def isprime(num):
limit = sqrt(num)
for prime in list_prime:
if num % prime == 0: return 0
if prime > limit: break
return 1
def generate_primes(no_of_primes):
o = 0
n = 11
w = wheel2357
l = len(w)
while len(list_prime) < no_of_primes:
i = n
n = n + w[o]
o = (o + 1) % l
if isprime(i):
list_prime.append(i)
t0 = time.time()
generate_primes(10001)
print list_prime[-1] # 104743
t1 = time.time()
print t1-t0 # 0.18 seconds
prints:
104743
0.307313919067

Categories

Resources