Project Euler 10th problem:
Find the sum of all the primes below two million.
Well I came up with two solutions :
USING GENERATOR FUNCTION
def gen_primes():
n = 2
primes = []
while True:
for p in primes:
if n % p == 0:
break
else:
primes.append(n)
yield n
n += 1
flag = True
sum=0
p=gen_primes()
while flag:
prime=p.__next__()
if prime > 2000000:
flag = False
else:
sum+=prime
print(sum)
W/O GENERATOR
def prime(number):
if number ==1:
return -1
else:
for a in (range(1,int(number**0.5)+1))[::2]:
if number%a==0 and a!=1:
return False
else:
return True
count=2
for i in (range(1,2000000))[::2]:
if prime(i)==True and i!=1:
count+=i
else:
continue
print(count)
Surprisingly, the latter (w/o g) takes 7.4 seconds whereas the former (using g) takes around 10 minutes !!!
Why is it so? Thought the generator would perform better because of fewer steps.
Your generator is doing a lot of unnecessary work. It checks all primes up to n when it only needs to check primes up to the square root of n. Here is a modified version of your generator function with the unnecessary work removed:
from time import time
t = time()
def gen_primes():
primes = []
yield 2
n = 3
while True:
is_prime = True
upper_limit = n ** .5
for p in primes:
if n % p == 0:
is_prime = False
break
elif p > upper_limit:
break
if is_prime:
primes.append(n)
yield n
n += 2 # only need to check divisibility by odd numbers
sum = 0
for prime in gen_primes():
if prime > 2_000_000:
break
else:
sum += prime
print("time:", time() - t)
print(sum)
This takes 2.3 seconds on my computer. The version without the generator takes 4.8 seconds on my computer.
If you're interested in a much more efficient algorithm for finding prime numbers, check out the Sieve of Eratosthenes.
https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
Here's a rework of your generator code that's almost twice as fast as the non-generator code. Similar to #DanielGiger's solution (+1) but attempts to be simpler and possibly a hair faster. It uses multiple squaring instead of a single square root (may or may not win out) and doesn't need a boolean flag:
def gen_primes():
yield 2
primes = [2]
number = 3
while True:
for prime in primes:
if prime * prime > number:
yield number
primes.append(number)
break
if number % prime == 0:
break
number += 2
total = 0
generator = gen_primes()
while True:
prime = next(generator)
if prime > 2_000_000:
break
total += prime
print(total)
Here's an equivalent rework of your non-generator code that also attempts to be simpler and just a hair faster. My rule of thumb is to deal with 2 and less as special cases and then write a clean odd divisor check:
def is_prime(number):
if number < 2:
return False
if number % 2 == 0:
return number == 2
for divisor in range(3, int(number**0.5) + 1, 2):
if number % divisor == 0:
return False
return True
total = 2
for i in range(3, 2_000_000, 2):
if is_prime(i):
total += i
print(total)
Also, your code generates an entire range of numbers and then throws away the even numbers -- we can use the third argument to range() to generate only the odd numbers in the first place.
In the end, the use of a generator has nothing to do with the general performance of your two solutions. You can rewrite your second solution as a generator:
def gen_primes():
yield 2
number = 3
while True:
for divisor in range(3, int(number**0.5) + 1, 2):
if number % divisor == 0:
break
else: # no break
yield number
number += 2
The difference between the two solutions is one uses only primes as trial divisors (at the cost of storage) and the other uses odd numbers (pseudoprimes) as trial divisors (with no storage cost). Time-wise, the one that does fewer trial divisions, wins.
I know that python is "slow as dirt", but i would like to make a fast and efficient program that finds primes. This is what i have:
num = 5 #Start at five, 2 and 3 are printed manually and 4 is a multiple of 2
print("2")
print("3")
def isPrime(n):
#It uses the fact that a prime (except 2 and 3) is of form 6k - 1 or 6k + 1 and looks only at divisors of this form.
i = 5
w = 2
while (i * i <= n): #You only need to check up too the square root of n
if (n % i == 0): #If n is divisable by i, it is not a prime
return False
i += w
w = 6 - w
return True #If it isn´t ruled out by now, it is a prime
while True:
if ((num % 2 != 0) and (num % 3 != 0)): #save time, only run the function of numbers that are not multiples of 2 or 3
if (isPrime(num) == True):
print(num) #print the now proved prime out to the screen
num += 2 #You only need to check odd numbers
Now comes my questions:
-Does this print out ALL prime numbers?
-Does this print out any numbers that aren't primes?
-Are there more efficient ways(there probably are)?
-How far will this go(limitations of python), and are there any ways to increase upper limit?
Using python 2.7.12
Does this print out ALL prime numbers?
There are infinitely many primes, as demonstrated by Euclid around 300 BC. So the answer to that question is most likely no.
Does this print out any numbers that aren't primes?
By the looks of it, it doesn't. However, to be sure; why not write a unit test?
Are there more efficient ways(there probably are)? -How far will this go(limitations of python), and are there any ways to increase upper limit?
See Fastest way to list all primes below N or Finding the 10001st prime - how to optimize?
Checking for num % 2 != 0 even though you increment by 2 each time seems pointless.
I have found that this algorithm is faster:
primes=[]
n=3
print("2")
while True:
is_prime=True
for prime in primes:
if n % prime ==0:
is_prime=False
break
if prime*prime>n:
break
if is_prime:
primes.append(n)
print (n)
n+=2
This is very simple. The function below returns True if num is a prime, otherwise False. Here, if we find a factor, other than 1 and itself, then we early stop the iterations because the number is not a prime.
def is_this_a_prime(num):
if num < 2 : return False # primes must be greater than 1
for i in range(2,num): # for all integers between 2 and num
if(num % i == 0): # search if num has a factor other than 1 and itself
return False # if it does break, no need to search further, return False
return True # if it doesn't we reached that point, so num is a prime, return True
I tried to optimize the code a bit, and this is what I've done.Instead of running the loop for n or n/2 times, I've done it using a conditional statements.(I think it's a bit faster)
def prime(num1, num2):
import math
def_ = [2,3,5,7,11]
result = []
for i in range(num1, num2):
if i%2!=0 and i%3!=0 and i%5!=0 and i%7!=0 and i%11!=0:
x = str(math.sqrt(i)).split('.')
if int(x[1][0]) > 0:
result.append(i)
else:
continue
return def_+result if num1 < 12 else result
I'm trying the following approach for generating primes:
primes = [2]
candidate = 3
MILLION = 1000000
while candidate < MILLION:
if all(candidate % prime for prime in primes if prime**2 <= candidate):
primes.append(candidate)
candidate += 2
However, this is comparatively much slower than my previous code, where I wasn't using the all function, and was making the checks myself as below:
primes = [2]
candidate = 3
MILLION = 1000000
while candidate < MILLION:
can_be_prime = True
for p in primes:
if p**2 > candidate:
break
elif candidate % p == 0:
can_be_prime = False
break
if can_be_prime:
primes.append(candidate)
candidate += 2
While the second one gets over within 10 seconds, the first one takes forever to complete. Can someone help me understand why the first one starts outputting so slowly after the first 100000 numbers?
While your idea to shorten the code using that generator expression and any is good, they are not equivalent. In particular, in your longer solution, you are iterating the (sorted) list of primes and break the iteration as soon as you found a prime for which p ** 2 > candidate is true.
In your generator expression however, you try to make this check using x for p in primes if p ** 2 <= candidate. This is unfortunately not the same. Even if that check fails, the generator will still continue to iterate over the remaining primes, performing that p ** 2 for every single prime, on every iteration of the outer while loop.
You can verify that this is the problem, if you write it a bit differently:
def getPrimes (candidate):
for p in primes:
if p ** 2 > candidate:
break
yield p
while candidate < MILLION:
if all(candidate % prime for prime in getPrimes(candidate)):
primes.append(candidate)
candidate += 2
So now, we’re using the same idea from the longer version and abort the iteration on primes as soon as we hit a prime for which p ** 2 > candidate is true. That way, we get the speed from the longer solution back.
we can actually use 6n +/- 1 rule for generating primes.
for example if you want to generate primes for a given number:
def primes(N):
if N == 2:
primes = [2]
elif N >= 3:
primes = [2, 3]
else:
return None
for i in range(6, N):
if i % 6 == 0:
left = i - 1
right = i + 1
if all(left % p != 0 for p in primes):
primes.append(left)
if all(right % p != 0 for p in primes):
primes.append(right)
return primes
I'm truly a beginner at python so I apologise for the lack of knowledge, but the reason I'm asking is that reading the Python manual and tutorial (http://docs.python.org/2.7/tutorial) I'm not unable to totally grasp how loops work. I've written some simple programs so I think I get the basics but for whatever reason this program that is meant to list all primes less than or equal to n is not working:
n = int(raw_input("What number should I go up to? "))
p = 2
while p <= n:
for i in range(2, p):
if p%i == 0:
p=p+1
print "%s" % p,
p=p+1
print "Done"
The output when I enter 100 for example is:
2 3 5 7 11 13 17 19 23 27 29 31 35 37 41 43 47 53 59 61 67 71 73 79 83 87 89 95 97 101 Done
Which looks almost right but for some reason contains 27, 35, 95, which are composite of course. I've been trying to pick apart the way my loop works but I just don't see where it skips checking for divisibility suddenly. I figured that if someone had a look they could explain to me what about the syntax is causing this. Thanks a bunch!
I would actually restructure the program to look like this:
for p in range(2, n+1):
for i in range(2, p):
if p % i == 0:
break
else:
print p,
print 'Done'
This is perhaps a more idiomatic solution (using a for loop instead of a while loop), and works perfectly.
The outer for loop iterates through all the numbers from 2 to n.
The inner one iterates to all numbers from 2 to p. If it reaches a number that divides evenly into p, then it breaks out of the inner loop.
The else block executes every time the for loop isn't broken out of (printing the prime numbers).
Then the program prints 'Done' after it finishes.
As a side note, you only need to iterate through 2 to the square root of p, since each factor has a pair. If you don't get a match there won't be any other factors after the square root, and the number will be prime.
Your code has two loops, one inside another. It should help you figure out the code if you replace the inner loop with a function. Then make sure the function is correct and can stand on its own (separate from the outer loop).
Here is my rewrite of your original code. This rewrite works perfectly.
def is_prime(n):
i = 2
while i < n:
if n%i == 0:
return False
i += 1
return True
n = int(raw_input("What number should I go up to? "))
p = 2
while p <= n:
if is_prime(p):
print p,
p=p+1
print "Done"
Note that is_prime() doesn't touch the loop index of the outer loop. It is a stand-alone pure function. Incrementing p inside the inner loop was the problem, and this decomposed version doesn't have the problem.
Now we can easily rewrite using for loops and I think the code gets improved:
def is_prime(n):
for i in range(2, n):
if n%i == 0:
return False
return True
n = int(raw_input("What number should I go up to? "))
for p in range(2, n+1):
if is_prime(p):
print p,
print "Done"
Note that in Python, range() never includes the upper bound that you pass in. So the inner loop, which checks for < n, we can simply call range(2, n) but for the outer loop, where we want <= n, we need to add one to n so that n will be included: range(2, n+1)
Python has some built-in stuff that is fun. You don't need to learn all these tricks right away, but here is another way you can write is_prime():
def is_prime(n):
return not any(n%i == 0 for i in range(2, n))
This works just like the for loop version of is_prime(). It sets i to values from range(2, n) and checks each one, and if a test ever fails it stops checking and returns. If it checks n against every number in the range and not any of them divide n evenly, then the number is prime.
Again, you don't need to learn all these tricks right away, but I think they are kind of fun when you do learn them.
This should work and is bit more optimized
import math
for i in range(2, 99):
is_prime = True
for j in range(2, int(math.sqrt(i)+1)):
if i % j == 0:
is_prime = False
if is_prime:
print(i)
Please compare your snippet with the one pasted below and you will notice where you were wrong.
n = int(raw_input("What number should I go up to? "))
p = 2
while p <= n:
is_prime=True
for i in range(2, p):
if p%i == 0:
is_prime=False
break;
if is_prime==True:
print "%d is a Prime Number\n" % p
p=p+1
you do not re-start the i loop after you find a non-prime
p = i = 2
while p <= n:
i = 2
while i < p:
if p%i == 0:
p += 1
i = 1
i += 1
print p,
p += 1
print "Done"
A while loop executes the body, and then checks if the condition at the top is True, if it is true, it does the body again. A for loop executes the body once for each item in the iterator.
def is_prime(n):
if n>=2:
for i in range(2, n):
if n%i == 0:
return False
return True
else:
return False
To find PRIME NUMBER
Let's do a couple more improvements.
You know 2 is the only even prime number, so you add 2 in your list and start from 3 incrementing your number to be checked by 2.
Once you are past the half-way point (see above sqrt and * examples), you don't need to test for a prime number.
If you use a list to keep track of the prime numbers, all you need to do is to divide by those prime numbers.
I wrote my code and each of the above items would improve my code execution time by about 500%.
prime_list=[2]
def is_prime(a_num):
for i in prime_list:
div, rem = divmod(a_num, i)
if rem == 0:
return False
elif div < i:
break;
prime_list.append(a_num)
return True
This in my opinion is a more optimised way. This finds all the prime numbers up to 1,000,000 in less than 8 seconds on my setup.
It is also one of my very first attempts at python, so I stand to be corrected
class prime:
def finder (self):
import math
n = long(raw_input("What number should I go up to? "))
for i in range(2, n):
is_prime = True
if i % 2 == 0:
is_prime = False
for j in range(3, long(math.sqrt(i) + 1), 2):
if i % j == 0:
is_prime = False
break
if is_prime:
print(i)
prime().finder()
print('Enter a Number: ')
number=abs(int(input()))
my_List=[0,1]
def is_prime(n):
if n in my_List:
return True
elif n>=2:
for i in range(2, n):
if n%i == 0:
return False
return True
else:
return False
if is_prime(number):
print("%d is Prime!"%number)
else:
print(number,'is not prime')
for i in range(2, p):
if p%i == 0:
p=p+1
print "%s" % p,
p=p+1
I am going to tell your error only,in line 3 you are incrimenting p but actually what you are missing is your i if your i in previous case is let say 13 then it will check your loop after 13 but it is leaving 2,3,5,7,11 so its an error .that is what happening in case of 27 your i before 27 is 13 and now it will check from 14.and I don't think u need an solution.
def findprime(num):
count = 0
for i in range(1,num+1):
list1 = []
for ch in range(1,i+1):
if i%1==0 and i%ch==0:
list1.append(ch)
if len(list1)==2:
count += 1
print(i,end=", ")
print()
return count
num2 = int(input("enter a number: "))
result=findprime(num2)
print("prime numbers between 1 and",num2,"are",result)
Here's a more extensive example with optimization in mind for Python 3.
import sys
inner_loop_iterations: int = 0
def is_prime(n):
a: int = 2
global inner_loop_iterations
if n == 1:
return("Not prime")
elif n == 2:
return("Prime")
while a * a <= n + 1:
inner_loop_iterations += 1
# This if statement reduces the number of inner loop iterations by roughy 50%
# just weeding out the even numbers.
if a % 2 == 0:
a += 1
else:
a += 2
if n % 2 == 0 or n % a == 0:
return ("Not prime")
else:
return ("Prime")
while True:
sys.stdout.write("Enter number to see if it's prime ('q' to quit): ")
n = input()
if not n:
continue
if n == 'q':
break
try:
n = int(n)
except ValueError:
print("Please enter a valid number")
if n < 1:
print("Please enter a valid number")
continue
sys.stdout.write("{}\n".format(is_prime(n)))
sys.stderr.write("Inner loops: {}\n\n".format(inner_loop_iterations))
inner_loop_iterations=0
This program has two main optimizations, first it only iterates from 2 to the square root of n and it only iterates through odd numbers. Using these optimizations I was able to find out that the number 1000000007 is prime in only 15811 loop iterations.
My fast implementation returning the first 25 primes:
#!/usr/bin/env python3
from math import sqrt
def _is_prime(_num: int = None):
if _num < 2:
return False
if _num > 3 and not (_num % 2 and _num % 3):
return False
return not any(_num % _ == 0 for _ in range(3, int(sqrt(_num) + 1), 2))
_cnt = 0
for _ in range(1, 1000):
if _is_prime(_):
_cnt += 1
print(f"Prime N°: {_:,} | Count: {_cnt:,}")
Better use
for i in range(2, p//2 + 1):
I recently started messing around with python and I wrote a program to print out the 1000th prime number but the output only shows a blinking cursor , the code is shown below:
number = 3
count= 1
while count <= 1000:
prime = True
for x in range(2, number):
if number % x == 0:
prime= False
if prime == True:
count = count + 1
if count <= 1000:
number = number + 1
print number
Any help and concise explanation would be appreciated
edit: i just realized the problem. #tichodroma solved the problem but did so by editing the OP post. so when i got to it it was already solved, how ever, he solved it by putting the print into the loop, hence the many numbers waterfall. but it should be outside the loop so as to only show the final result. also - after looking at the OP code before edit, it was written in such a way that it was taking a long time to run, and the "blinking line" was the system working in the background
def isprime(n):
'''check if integer n is a prime'''
# make sure n is a positive integer
n = abs(int(n))
# 0 and 1 are not primes
if n < 2:
return False
# 2 is the only even prime number
if n == 2:
return True
# all other even numbers are not primes
if not n & 1:
return False
# range starts with 3 and only needs to go up the squareroot of n
# for all odd numbers
for x in range(3, int(n**0.5)+1, 2):
if n % x == 0:
return False
return True
counter = 0
number = 0
while True:
if isprime(number):
counter+=1
if counter == 10000:
break
number+=1
print number