Print series of prime numbers in python
I was having issues in printing a series of prime numbers from one to hundred. I can't figure our what's wrong with my code.
Here's what I wrote; it prints all the odd numbers instead of primes:
for num in range(1, 101):
for i in range(2, num):
if num % i == 0:
break
else:
print(num)
break
You need to check all numbers from 2 to n-1 (to sqrt(n) actually, but ok, let it be n).
If n
is divisible by any of the numbers, it is not prime. If a number is prime, print it.
for num in range(2,101):
prime = True
for i in range(2,num):
if (num%i==0):
prime = False
if prime:
print (num)
You can write the same much shorter and more pythonic:
for num in range(2,101):
if all(num%i!=0 for i in range(2,num)):
print (num)
As I've said already, it would be better to check divisors not from 2 to n-1, but from 2 to sqrt(n):
import math
for num in range(2,101):
if all(num%i!=0 for i in range(2,int(math.sqrt(num))+1)):
print (num)
For small numbers like 101 it doesn't matter, but for 10**8 the difference will be really big.
You can improve it a little more by incrementing the range you check by 2, and thereby only checking odd numbers. Like so:
import math
print 2
for num in range(3,101,2):
if all(num%i!=0 for i in range(2,int(math.sqrt(num))+1)):
print (num)
Edited:
As in the first loop odd numbers are selected, in the second loop no need to check with even numbers, so 'i' value can be start with 3 and skipped by 2.
import math
print 2
for num in range(3,101,2):
if all(num%i!=0 for i in range(3,int(math.sqrt(num))+1, 2)):
print (num)
Instead of trial division, a better approach, invented by the Greek mathematician Eratosthenes over two thousand years ago, is to sieve by repeatedly casting out multiples of primes.
Begin by making a list of all numbers from 2 to the maximum desired prime n. Then repeatedly take the smallest uncrossed number and cross out all of its multiples; the numbers that remain uncrossed are prime.
For example, consider the numbers less than 30. Initially, 2 is identified as prime, then 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28 and 30 are crossed out. Next 3 is identified as prime, then 6, 9, 12, 15, 18, 21, 24, 27 and 30 are crossed out. The next prime is 5, so 10, 15, 20, 25 and 30 are crossed out. And so on. The numbers that remain are prime: 2, 3, 5, 7, 11, 13, 17, 19, 23, and 29.
def primes(n):
sieve = [True] * (n+1)
for p in range(2, n+1):
if (sieve[p]):
print p
for i in range(p, n+1, p):
sieve[i] = False
An optimized version of the sieve handles 2 separately and sieves only odd numbers. Also, since all composites less than the square of the current prime are crossed out by smaller primes, the inner loop can start at p^2 instead of p and the outer loop can stop at the square root of n. I'll leave the optimized version for you to work on.
break
ends the loop that it is currently in. So, you are only ever checking if it divisible by 2, giving you all odd numbers.
for num in range(2,101):
for i in range(2,num):
if (num%i==0):
break
else:
print(num)
that being said, there are much better ways to find primes in python than this.
for num in range(2,101):
if is_prime(num):
print(num)
def is_prime(n):
for i in range(2, int(math.sqrt(n)) + 1):
if n % i == 0:
return False
return True
I'm a proponent of not assuming the best solution and testing it. Below are some modifications I did to create simple classes of examples by both @igor-chubin and @user448810. First off let me say it's all great information, thank you guys. But I have to acknowledge @user448810 for his clever solution, which turns out to be the fastest by far (of those I tested). So kudos to you, sir! In all examples I use a values of 1 million (1,000,000) as n.
Please feel free to try the code out.
Good luck!
Method 1 as described by Igor Chubin:
def primes_method1(n):
out = list()
for num in range(1, n+1):
prime = True
for i in range(2, num):
if (num % i == 0):
prime = False
if prime:
out.append(num)
return out
Benchmark: Over 272+ seconds
Method 2 as described by Igor Chubin:
def primes_method2(n):
out = list()
for num in range(1, n+1):
if all(num % i != 0 for i in range(2, num)):
out.append(num)
return out
Benchmark: 73.3420000076 seconds
Method 3 as described by Igor Chubin:
def primes_method3(n):
out = list()
for num in range(1, n+1):
if all(num % i != 0 for i in range(2, int(num**.5 ) + 1)):
out.append(num)
return out
Benchmark: 11.3580000401 seconds
Method 4 as described by Igor Chubin:
def primes_method4(n):
out = list()
out.append(2)
for num in range(3, n+1, 2):
if all(num % i != 0 for i in range(2, int(num**.5 ) + 1)):
out.append(num)
return out
Benchmark: 8.7009999752 seconds
Method 5 as described by user448810 (which I thought was quite clever):
def primes_method5(n):
out = list()
sieve = [True] * (n+1)
for p in range(2, n+1):
if (sieve[p]):
out.append(p)
for i in range(p, n+1, p):
sieve[i] = False
return out
Benchmark: 1.12000012398 seconds
Notes: Solution 5 listed above (as proposed by user448810) turned out to be the fastest and honestly quiet creative and clever. I love it. Thanks guys!!
EDIT: Oh, and by the way, I didn't feel there was any need to import the math library for the square root of a value as the equivalent is just (n**.5). Otherwise I didn't edit much other then make the values get stored in and output array to be returned by the class. Also, it would probably be a bit more efficient to store the results to a file than verbose and could save a lot on memory if it was just one at a time but would cost a little bit more time due to disk writes. I think there is always room for improvement though. So hopefully the code makes sense guys.
2021 EDIT: I know it's been a really long time but I was going back through my Stackoverflow after linking it to my Codewars account and saw my recently accumulated points, which which was linked to this post. Something I read in the original poster caught my eye for @user448810, so I decided to do a slight modification mentioned in the original post by filtering out odd values before appending the output array. The results was much better performance for both the optimization as well as latest version of Python 3.8 with a result of 0.723 seconds (prior code) vs 0.504 seconds using 1,000,000 for n.
def primes_method5(n):
out = list()
sieve = [True] * (n+1)
for p in range(2, n+1):
if (sieve[p] and sieve[p]%2==1):
out.append(p)
for i in range(p, n+1, p):
sieve[i] = False
return out
Nearly five years later, I might know a bit more but I still just love Python, and it's kind of crazy to think it's been that long. The post honestly feels like it was made a short time ago and at the time I had only been using python about a year I think. And it still seems relevant. Crazy. Good times.
The best way to solve the above problem would be to use the "Miller Rabin Primality Test" algorithm. It uses a probabilistic approach to find if a number is prime or not. And it is by-far the most efficient algorithm I've come across for the same.
The python implementation of the same is demonstrated below:
def miller_rabin(n, k):
# Implementation uses the Miller-Rabin Primality Test
# The optimal number of rounds for this test is 40
# See http://stackoverflow.com/questions/6325576/how-many-iterations-of-rabin-miller-should-i-use-for-cryptographic-safe-primes
# for justification
# If number is even, it's a composite number
if n == 2:
return True
if n % 2 == 0:
return False
r, s = 0, n - 1
while s % 2 == 0:
r += 1
s //= 2
for _ in xrange(k):
a = random.randrange(2, n - 1)
x = pow(a, s, n)
if x == 1 or x == n - 1:
continue
for _ in xrange(r - 1):
x = pow(x, 2, n)
if x == n - 1:
break
else:
return False
return True