Can this be made more pythonic? - python

I came across this (really) simple program a while ago. It just outputs the first x primes. I'm embarrassed to ask, is there any way to make it more "pythonic" ie condense it while making it (more) readable? Switching functions is fine; I'm only interested in readability.
Thanks
from math import sqrt
def isprime(n):
if n ==2:
return True
if n % 2 ==0 : # evens
return False
max = int(sqrt(n))+1 #only need to search up to sqrt n
i=3
while i <= max: # range starts with 3 and for odd i
if n % i == 0:
return False
i+=2
return True
reqprimes = int(input('how many primes: '))
primessofar = 0
currentnumber = 2
while primessofar < reqprimes:
result = isprime(currentnumber)
if result:
primessofar+=1
print currentnumber
#print '\n'
currentnumber += 1

Your algorithm itself may be implemented pythonically, but it's often useful to re-write algorithms in a functional way - You might end up with a completely different but more readable solution at all (which is even more pythonic).
def primes(upper):
n = 2; found = []
while n < upper:
# If a number is not divisble through all preceding primes, it's prime
if all(n % div != 0 for div in found):
yield n
found.append( n )
n += 1
Usage:
for pr in primes(1000):
print pr
Or, with Alasdair's comment taken into account, a more efficient version:
from math import sqrt
from itertools import takewhile
def primes(upper):
n = 2; foundPrimes = []
while n < upper:
sqrtN = int(sqrt(n))
# If a number n is not divisble through all preceding primes up to sqrt(n), it's prime
if all(n % div != 0 for div in takewhile(lambda div: div <= sqrtN, foundPrimes)):
yield n
foundPrimes.append(n)
n += 1

The given code is not very efficient. Alternative solution (just as inefficient):†
>>> from math import sqrt
>>> def is_prime(n):
... return all(n % d for d in range(2, int(sqrt(n)) + 1))
...
>>> def primes_up_to(n):
... return filter(is_prime, range(2, n))
...
>>> list(primes_up_to(20))
[2, 3, 5, 7, 11, 13, 17, 19]
This code uses all, range, int, math.sqrt, filter and list. It is not completely identical to your code, as it prints primes up to a certain number, not exactly n primes. For that, you can do:
>>> from itertools import count, islice
>>> def n_primes(n):
... return islice(filter(is_prime, count(2)), n)
...
>>> list(n_primes(10))
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
That introduces another two functions, namely itertools.count and itertools.islice. (That last piece of code works only in Python 3.x; in Python 2.x, use itertools.ifilter instead of filter.)
†: A more efficient method is to use the Sieve of Eratosthenes.

A few minor things from the style guide.
Uses four spaces, not two. (Personally I prefer tabs, but that's not the Pythonic way.)
Fewer blank lines.
Consistent whitespace: n ==2: => n == 2:
Use underscores in your variables names: currentnumber => current_number

Firstly, you should not assign max to a variable as it is an inbuilt function used to find the maximum value from an iterable. Also, that entire section of code can instead be written as
for i in xrange(3, int(sqrt(n))+1, 2):
if n%i==0: return False
Also, instead of defining a new variable result and putting the value returned by isprime into it, you can just directly do
if isprime(currentnumber):

I recently found Project Euler solutions in functional python and it has some really nice examples of working with primes like this. Number 7 is pretty close to your problem:
def isprime(n):
"""Return True if n is a prime number"""
if n < 3:
return (n == 2)
elif n % 2 == 0:
return False
elif any(((n % x) == 0) for x in xrange(3, int(sqrt(n))+1, 2)):
return False
return True
def primes(start=2):
"""Generate prime numbers from 'start'"""
return ifilter(isprime, count(start))

Usually you don't use while loops for simple things like this. You rather create a range object and get the elements from there. So you could rewrite the first loop to this for example:
for i in range( 3, int( sqrt( n ) ) + 1, 2 ):
if n % i == 0:
return False
And it would be a lot better if you would cache your prime numbers and only check the previous prime numbers when checking a new number. You can save a lot time by that (and easily calculate larger prime numbers this way). Here is some code I wrote before to get all prime numbers up to n easily:
def primeNumbers ( end ):
primes = []
primes.append( 2 )
for i in range( 3, end, 2 ):
isPrime = True
for j in primes:
if i % j == 0:
isPrime = False
break
if isPrime:
primes.append( i )
return primes
print primeNumbers( 20 )

Translated from the brilliant guys at stacktrace.it (Daniele Varrazzo, specifically), this version takes advantage of a binary min-heap to solve this problem:
from heapq import heappush, heapreplace
def yield_primes():
"""Endless prime number generator."""
# Yield 2, so we don't have to handle the empty heap special case
yield 2
# Heap of (non-prime, prime factor) tuples.
todel = [ (4, 2) ]
n = 3
while True:
if todel[0][0] != n:
# This number is not on the head of the heap: prime!
yield n
heappush(todel, (n*n, n)) # add to heap
else:
# Not prime: add to heap
while todel[0][0] == n:
p = todel[0][1]
heapreplace(todel, (n+p, p))
# heapreplace pops the minimum value then pushes:
# heap size is unchanged
n += 1
This code isn't mine and I don't understand it fully (but the explaination is here :) ), so I'm marking this answer as community wiki.

You can make it more pythonic with sieve algorithm (all primes small than 100):
def primes(n):
sieved = set()
for i in range(2, n):
if not(i in sieved):
for j in range(i + i, n, i):
sieved.add(j)
return set(range(2, n)) - sieved
print primes(100)
A very small trick will turn it to your goal.

Related

Most efficient way to filter prime numbers from a list of random numbers in Python

I have a list filled with random numbers and I want to return the prime numbers from this list. So I created these functions:
def is_prime(number):
for i in range(2, int(sqrt(number)) + 1):
if number % i == 0:
return False
return number > 1
And
def filter_primes(general_list):
return set(filter(is_prime, general_list))
But I want to improve performance, so how can I achieve this?
Sieve of Eratosthenes, taking about 0.17 seconds for primes under 10 million on PyPy 3.5 on my device:
from array import array
from math import isqrt
def primes(upper):
numbers = array('B', [1]) * (upper + 1)
for i in range(2, isqrt(upper) + 1):
if numbers[i]:
low_multiple = i * i
numbers[low_multiple:upper + 1:i] = array('B', [0]) * ((upper - low_multiple) // i + 1)
return {i for i, x in enumerate(numbers) if i >= 2 and x}
and the filter function:
filter_primes = primes(10_000_000).intersection
3 rounds of the the Miller-Rabin test ( https://en.wikipedia.org/wiki/Miller%2dRabin_primality_test ) using bases 2, 7, and 61, is known to accurately detect all primes <= 32 bit, i.e., anything that fits into a python int.
This is much, much faster than trial division or sieving if the numbers can be large.
If the numbers cannot be large (i.e., < 10,000,000 as you suggest in comments), then you may want to precompute the set of all primes < 10,000,000, but there are over 600,000 of those.
How about this? I think It's a little better:
def filter_primes(general_list):
return filter(is_prime, set(general_list))
This way we don't call is_prime() for same number multiple times.
The Sieve of Eratosthenes is more efficient than Trial Division, the method you are using.
Your trial division loop can be made more efficient, taking about half the time. Two is the only even prime number, so treat two as a special case and only deal with odd numbers thereafter, which will halve the work.
My Python is non-existent, but this pseudocode should make things clear:
def isPrime(num)
// Low numbers.
if (num <= 1)
return false
end if
// Even numbers
if (num % 2 == 0)
return (num == 2) // 2 is the only even prime.
end if
// Odd numbers
for (i = 3 to sqrt(num) + 1 step 2)
if (num % i == 0)
return false
end if
end for
// If we reach here, num is prime.
return true;
end def
That step 2 in the for loop is what halves the work. Having earlier eliminated all even numbers you only need to test with odd trial divisors: 3, 5, 7, ...
def primes_list(num_list):
divs = [2,3,5,7]
primes = [x for x in set(num_list) if 0 not in {1 if ((x%i != 0) | (x in divs)) & (x > 0) else 0 for i in divs}]
return primes
For this function, it takes a list, num_list, as a parameter. divs is a predefined, or rather hard coded, list of prime numbers less than 10 excluding 1. Then we use list comprehension to filter num_list for prime numbers as the variable primes.
This is one more flavour of code to find the prime no of the range. The simple and easy way.
def find_prime(n):
if n <=1:
return False
else:
for i in range(2, n):
if n % i == 0:
return False
return True
n = 10
x = filter(find_prime, range(n)) #you can give random no list too
print(list(x))
def is_prime(n):
if n>1:
for i in range(2,int(n**0.5)+1):
if n%i==0:
return False
return True
else: return False
print([x for x in general_list if is_prime(x)])
would you try this... There is no need for the filter at all and you could simply apply set() to the general_list if there are duplicate elements in the list to optimize more.

Prime number calculator produces no output (python)

I am trying to find the 10001st prime using a basic logic:
1) Identify if a number is prime
2) Add it to a list if prime
3) Print the 10001st term in the list
Here is my code:
primelist=[]
import math
i=2
while True:
for x in range(2, int(math.sqrt(i))):
if i % x == 0:
continue
else:
primelist.append(i)
if len(primelist)== 10001:
break
print(primelist[-1])
Is the logic or code fundamentally wrong or inefficient?
What can I do to ameliorate/ make it work?
EDIT
I have incremented i (i+=1) and used all() to check if everything was indivisible, in response to comments
primelist=[2]
import math
i=3
while True:
for x in range(2, int(i**(1/2))):
if all(i%x!=0 for x in range(2, int(math.sqrt(i)))):
primelist.append(i)
i+=1
if len(primelist)== 10001:
break
print(primelist[-1])
Keep the algorithm/code structure the same (no optimization done), so we can easily share several language points, please see inline comments:
primelist=[]
import math
i=2
while True:
#changed to sqrt + 1, the second parameter of range is not inclusive,
#by adding 1, we make sure sqrt itself is included
for x in range(2, int(math.sqrt(i) + 1)):
if i % x == 0:
#you want break not continue, continue will try
#next possible factor, since you already figured out that this
#is not a prime, no need to keep trying
#continue
break
#a for/else block, many python users never encountered this python
#syntax. The else block is only triggered, if the for loop is naturally
#completed without running into the break statement
else:
#a little debugging, to visually confirm we generated all primes
print("adding {}".format(i))
primelist.append(i)
if len(primelist)== 11:
break
#advance to the next number, this is important,
#otherwise i will always be 2
i += 1
print(primelist[-1])
If you would like to optimize the algorithm, search online for "prime sieve".
This one should work if you want to stay with your algorithm:
import math
def is_prime(n):
for x in range(2, int(math.sqrt(n)) + 1):
if n % x == 0:
return False
return True
primelist = []
i = 2
while True:
if is_prime(i) is True:
primelist.append(i)
i += 1
if len(primelist) == 10001:
break
print(primelist[-1])
Here's a version of your code that's a bit faster, and which doesn't use much RAM. We really don't need to build a list of the primes we find. We don't use the numbers in that list to find more primes, and we're really only interested in its length. So instead of building a list we merely keep count of the primes we find.
# Include 2 in the count
count = 1
i = 3
while True:
if all(i % x for x in range(3, int(i ** 0.5) + 1, 2)):
count += 1
if count == 10001:
break
i += 2
print(i)
FWIW, here's a faster solution that uses sieving. We estimate the required size of the sieve using the prime number theorem. Wikipedia gives these bounds for p(n), the n'th prime number, which is valid for n >= 6:
log(n) + log(log(n)) - 1 < p(n) / n < log(n) + log(log(n))
We use the upper bound as the highest number in the sieve. For n < 6 we use a hard-coded list.
To save space, this sieve only holds odd numbers, so we treat the case of p(1) == 2 as a special case.
#!/usr/bin/env python3
''' Use a sieve of Eratosthenes to find nth prime
Written by PM 2Ring 2017.05.01
Sieve code derived from primes1 by Robert William Hanks
See http://stackoverflow.com/a/3035188/4014959
'''
from math import log
from sys import argv
def main():
num = int(argv[1]) if len(argv) > 1 else 10001
if num == 1:
# Handle 2 as a special case
print(1, 2)
return
elif num < 6:
# Use a pre-built table for (3, 5, 7, 11)
primes = [1, 1, 1, 1, 0, 1]
else:
# Compute upper bound from Prime number theorem
x = log(num)
hi = int(num * (x + log(x)))
print('upper bound', hi)
# Create a boolean list of odd primes in range(hi)
primes = [True] * (hi//2)
for i in range(3, 1 + int(hi**0.5), 2):
if primes[i//2]:
primes[i*i//2::i] = [False] * ((hi - i*i - 1) // (2*i) + 1)
# Count the primes until we get the nth one
k = 0
for i, b in enumerate(primes):
if b:
k += 1
if k == num:
break
print(num, 2*i+1)
if __name__ == "__main__":
main()
This code finds p(10001) = 104743 in under 0.15 seconds on my old single core 32 bit 2GHz machine running Python 3.6.0. It finds p(500000) = 7368787 in about 2.2 seconds.

Beginner looking for advice/help on this code (Python) [duplicate]

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)
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.
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
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
Igor Chubin's answer can be improved. When testing if X is prime, the algorithm doesn't have to check every number up to the square root of X, it only has to check the prime numbers up to the sqrt(X). Thus, it can be more efficient if it refers to the list of prime numbers as it is creating it. The function below outputs a list of all primes under b, which is convenient as a list for several reasons (e.g. when you want to know the number of primes < b). By only checking the primes, it saves time at higher numbers (compare at around 10,000; the difference is stark).
from math import sqrt
def lp(b)
primes = [2]
for c in range(3,b):
e = round(sqrt(c)) + 1
for d in primes:
if d <= e and c%d == 0:
break
else:
primes.extend([c])
return primes
My way of listing primes to an entry number without too much hassle is using the property that you can get any number that is not a prime with the summation of primes.
Therefore, if you divide the entry number with all primes below it, and it is not evenly divisible by any of them, you know that you have a prime.
Of course there are still faster ways of getting the primes, but this one already performs quite well, especially because you are not dividing the entry number by any number, but quite only the primes all the way to that number.
With this code I managed on my computer to list all primes up to 100 000 in less than 4 seconds.
import time as t
start = t.clock()
primes = [2,3,5,7]
for num in xrange(3,100000,2):
if all(num%x != 0 for x in primes):
primes.append(num)
print primes
print t.clock() - start
print sum(primes)
A Python Program function module that returns the 1'st N prime numbers:
def get_primes(count):
"""
Return the 1st count prime integers.
"""
result = []
x=2
while len(result) in range(count):
i=2
flag=0
for i in range(2,x):
if x%i == 0:
flag+=1
break
i=i+1
if flag == 0:
result.append(x)
x+=1
pass
return result
A simpler and more efficient way of solving this is storing all prime numbers found previously and checking if the next number is a multiple of any of the smaller primes.
n = 1000
primes = [2]
for i in range(3, n, 2):
if not any(i % prime == 0 for prime in primes):
primes.append(i)
print(primes)
Note that any is a short circuit function, in other words, it will break the loop as soon as a truthy value is found.
we can make a list of prime numbers using sympy library
import sympy
lower=int(input("lower value:")) #let it be 30
upper=int(input("upper value:")) #let it be 60
l=list(sympy.primerange(lower,upper+1)) #[31,37,41,43,47,53,59]
print(l)
Here's a simple and intuitive version of checking whether it's a prime in a RECURSIVE function! :) (I did it as a homework assignment for an MIT class)
In python it runs very fast until 1900. IF you try more than 1900, you'll get an interesting error :) (Would u like to check how many numbers your computer can manage?)
def is_prime(n, div=2):
if div> n/2.0: return True
if n% div == 0:
return False
else:
div+=1
return is_prime(n,div)
#The program:
until = 1000
for i in range(until):
if is_prime(i):
print i
Of course... if you like recursive functions, this small code can be upgraded with a dictionary to seriously increase its performance, and avoid that funny error.
Here's a simple Level 1 upgrade with a MEMORY integration:
import datetime
def is_prime(n, div=2):
global primelist
if div> n/2.0: return True
if div < primelist[0]:
div = primelist[0]
for x in primelist:
if x ==0 or x==1: continue
if n % x == 0:
return False
if n% div == 0:
return False
else:
div+=1
return is_prime(n,div)
now = datetime.datetime.now()
print 'time and date:',now
until = 100000
primelist=[]
for i in range(until):
if is_prime(i):
primelist.insert(0,i)
print "There are", len(primelist),"prime numbers, until", until
print primelist[0:100], "..."
finish = datetime.datetime.now()
print "It took your computer", finish - now , " to calculate it"
Here are the resuls, where I printed the last 100 prime numbers found.
time and date: 2013-10-15 13:32:11.674448
There are 9594 prime numbers, until 100000
[99991, 99989, 99971, 99961, 99929, 99923, 99907, 99901, 99881, 99877, 99871, 99859, 99839, 99833, 99829, 99823, 99817, 99809, 99793, 99787, 99767, 99761, 99733, 99721, 99719, 99713, 99709, 99707, 99689, 99679, 99667, 99661, 99643, 99623, 99611, 99607, 99581, 99577, 99571, 99563, 99559, 99551, 99529, 99527, 99523, 99497, 99487, 99469, 99439, 99431, 99409, 99401, 99397, 99391, 99377, 99371, 99367, 99349, 99347, 99317, 99289, 99277, 99259, 99257, 99251, 99241, 99233, 99223, 99191, 99181, 99173, 99149, 99139, 99137, 99133, 99131, 99119, 99109, 99103, 99089, 99083, 99079, 99053, 99041, 99023, 99017, 99013, 98999, 98993, 98981, 98963, 98953, 98947, 98939, 98929, 98927, 98911, 98909, 98899, 98897] ...
It took your computer 0:00:40.871083 to calculate it
So It took 40 seconds for my i7 laptop to calculate it. :)
# computes first n prime numbers
def primes(n=1):
from math import sqrt
count = 1
plist = [2]
c = 3
if n <= 0 :
return "Error : integer n not >= 0"
while (count <= n - 1): # n - 1 since 2 is already in plist
pivot = int(sqrt(c))
for i in plist:
if i > pivot : # check for primae factors 'till sqrt c
count+= 1
plist.append(c)
break
elif c % i == 0 :
break # not prime, no need to iterate anymore
else :
continue
c += 2 # skipping even numbers
return plist
You are terminating the loop too early. After you have tested all possibilities in the body of the for loop, and not breaking, then the number is prime. As one is not prime you have to start at 2:
for num in xrange(2, 101):
for i in range(2,num):
if not num % i:
break
else:
print num
In a faster solution you only try to divide by primes that are smaller or equal to the root of the number you are testing. This can be achieved by remembering all primes you have already found. Additionally, you only have to test odd numbers (except 2). You can put the resulting algorithm into a generator so you can use it for storing primes in a container or simply printing them out:
def primes(limit):
if limit > 1:
primes_found = [(2, 4)]
yield 2
for n in xrange(3, limit + 1, 2):
for p, ps in primes_found:
if ps > n:
primes_found.append((n, n * n))
yield n
break
else:
if not n % p:
break
for i in primes(101):
print i
As you can see there is no need to calculate the square root, it is faster to store the square for each prime number and compare each divisor with this number.
How about this? Reading all the suggestions I used this:
prime=[2]+[num for num in xrange(3,m+1,2) if all(num%i!=0 for i in range(2,int(math.sqrt(num))+1))]
Prime numbers up to 1000000
root#nfs:/pywork# time python prime.py
78498
real 0m6.600s
user 0m6.532s
sys 0m0.036s
Adding to the accepted answer, further optimization can be achieved by using a list to store primes and printing them after generation.
import math
Primes_Upto = 101
Primes = [2]
for num in range(3,Primes_Upto,2):
if all(num%i!=0 for i in Primes):
Primes.append(num)
for i in Primes:
print i
Here is the simplest logic for beginners to get prime numbers:
p=[]
for n in range(2,50):
for k in range(2,50):
if n%k ==0 and n !=k:
break
else:
for t in p:
if n%t ==0:
break
else:
p.append(n)
print p
n = int(input())
is_prime = lambda n: all( n%i != 0 for i in range(2, int(n**.5)+1) )
def Prime_series(n):
for i in range(2,n):
if is_prime(i) == True:
print(i,end = " ")
else:
pass
Prime_series(n)
Here is a simplified answer using lambda function.
def function(number):
for j in range(2, number+1):
if all(j % i != 0 for i in range(2, j)):
print(j)
function(13)
for i in range(1, 100):
for j in range(2, i):
if i % j == 0:
break
else:
print(i)
Print n prime numbers using python:
num = input('get the value:')
for i in range(2,num+1):
count = 0
for j in range(2,i):
if i%j != 0:
count += 1
if count == i-2:
print i,
def prime_number(a):
yes=[]
for i in range (2,100):
if (i==2 or i==3 or i==5 or i==7) or (i%2!=0 and i%3!=0 and i%5!=0 and i%7!=0 and i%(i**(float(0.5)))!=0):
yes=yes+[i]
print (yes)
min=int(input("min:"))
max=int(input("max:"))
for num in range(min,max):
for x in range(2,num):
if(num%x==0 and num!=1):
break
else:
print(num,"is prime")
break
This is a sample program I wrote to check if a number is prime or not.
def is_prime(x):
y=0
if x<=1:
return False
elif x == 2:
return True
elif x%2==0:
return False
else:
root = int(x**.5)+2
for i in xrange (2,root):
if x%i==0:
return False
y=1
if y==0:
return True
n = int(raw_input('Enter the integer range to find prime no :'))
p = 2
while p<n:
i = p
cnt = 0
while i>1:
if p%i == 0:
cnt+=1
i-=1
if cnt == 1:
print "%s is Prime Number"%p
else:
print "%s is Not Prime Number"%p
p+=1
Using filter function.
l=range(1,101)
for i in range(2,10): # for i in range(x,y), here y should be around or <= sqrt(101)
l = filter(lambda x: x==i or x%i, l)
print l
for num in range(1,101):
prime = True
for i in range(2,num/2):
if (num%i==0):
prime = False
if prime:
print num
f=0
sum=0
for i in range(1,101):
for j in range(1,i+1):
if(i%j==0):
f=f+1
if(f==2):
sum=sum+i
print i
f=0
print sum
The fastest & best implementation of omitting primes:
def PrimeRanges2(a, b):
arr = range(a, b+1)
up = int(math.sqrt(b)) + 1
for d in range(2, up):
arr = omit_multi(arr, d)
Here is a different approach that trades space for faster search time. This may be fastest so.
import math
def primes(n):
if n < 2:
return []
numbers = [0]*(n+1)
primes = [2]
# Mark all odd numbers as maybe prime, leave evens marked composite.
for i in xrange(3, n+1, 2):
numbers[i] = 1
sqn = int(math.sqrt(n))
# Starting with 3, look at each odd number.
for i in xrange(3, len(numbers), 2):
# Skip if composite.
if numbers[i] == 0:
continue
# Number is prime. Would have been marked as composite if there were
# any smaller prime factors already examined.
primes.append(i)
if i > sqn:
# All remaining odd numbers not marked composite must be prime.
primes.extend([i for i in xrange(i+2, len(numbers), 2)
if numbers[i]])
break
# Mark all multiples of the prime as composite. Check odd multiples.
for r in xrange(i*i, len(numbers), i*2):
numbers[r] = 0
return primes
n = 1000000
p = primes(n)
print "Found", len(p), "primes <=", n
Adding my own version, just to show some itertools tricks v2.7:
import itertools
def Primes():
primes = []
a = 2
while True:
if all(itertools.imap(lambda p : a % p, primes)):
yield a
primes.append(a)
a += 1
# Print the first 100 primes
for _, p in itertools.izip(xrange(100), Primes()):
print p

Python Eratosthenes Sieve Algorithm Optimization

I'm attempting to implement the Sieve of Eratosthenes. The output seems to be correct (minus "2" that needs to be added) but if the input to the function is larger than 100k or so it seems to take an inordinate amount of time. What are ways that I can optimize this function?
def sieveErato(n):
numberList = range(3,n,2)
for item in range(int(math.sqrt(len(numberList)))):
divisor = numberList[item]
for thing in numberList:
if(thing % divisor == 0) and thing != divisor:
numberList.remove(thing)
return numberList
Your algorithm is not the Sieve of Eratosthenes. You perform trial division (the modulus operator) instead of crossing-off multiples, as Eratosthenes did over two thousand years ago. Here is an explanation of the true sieving algorithm, and shown below is my simple, straight forward implementation, which returns a list of primes not exceeding n:
def sieve(n):
m = (n-1) // 2
b = [True]*m
i,p,ps = 0,3,[2]
while p*p < n:
if b[i]:
ps.append(p)
j = 2*i*i + 6*i + 3
while j < m:
b[j] = False
j = j + 2*i + 3
i+=1; p+=2
while i < m:
if b[i]:
ps.append(p)
i+=1; p+=2
return ps
We sieve only on the odd numbers, stopping at the square root of n. The odd-looking calculations on j map between the integers being sieved 3, 5, 7, 9, ... and indexes 0, 1, 2, 3, ... in the b array of bits.
You can see this function in action at http://ideone.com/YTaMB, where it computes the primes to a million in less than a second.
You can try the same way Eratosthenes did. Take an array with all numbers you need to check order ascending, go to number 2 and mark it. Now scratch every second number till the end of the array. Then go to 3 and mark it. After that scratch every third number . Then go to 4 - it is already scratched, so skip it. Repeat this for every n+1 which is not already scratched.
In the end, the marked numbers are the prime one. This algorithm is faster, but sometimes need lots of memory. You can optimize it a little by drop all even numbers (cause they are not prime) and add 2 manually to the list. This will twist the logic a little, but will take half the memory.
Here is an illustration of what I'm talking about: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
Warning: removing elements from an iterator while iterating on it can be dengerous...
You could make the
if(thing % divisor == 0) and thing != divisor:
test lighter by splitting it in the loop that breaks when you arrive to the index of 'divisor' and then the test:
for thing in numberList_fromDivisorOn:
if(thing % divisor == 0):
numberList.remove(thing)
This code takes 2 seconds to generate primes less than 10M
(it is not mine, i found it somewer on google)
def erat_sieve(bound):
if bound < 2:
return []
max_ndx = (bound - 1) // 2
sieve = [True] * (max_ndx + 1)
#loop up to square root
for ndx in range(int(bound ** 0.5) // 2):
# check for prime
if sieve[ndx]:
# unmark all odd multiples of the prime
num = ndx * 2 + 3
sieve[ndx+num:max_ndx:num] = [False] * ((max_ndx-ndx-num-1)//num + 1)
# translate into numbers
return [2] + [ndx * 2 + 3 for ndx in range(max_ndx) if sieve[ndx]]
I followed this link: Sieve of Eratosthenes - Finding Primes Python as suggested by #MAK and I've found that the accepted answer could be improved with an idea I've found in your code:
def primes_sieve2(limit):
a = [True] * limit # Initialize the primality list
a[0] = a[1] = False
sqrt = int(math.sqrt(limit))+1
for i in xrange(sqrt):
isprime = a[i]
if isprime:
yield i
for n in xrange(i*i, limit, i): # Mark factors non-prime
a[n] = False
for (i, isprime) in enumerate(a[sqrt:]):
if isprime:
yield i+sqrt
if given unlimited memory and time, the following code will print all the prime numbers. and it'll do it without using trial division. it is based on the haskell code in the paper: The Genuine Sieve of Eratosthenes by Melissa E. O'Neill
from heapq import heappush, heappop, heapreplace
def sieve():
w = [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]
for p in [2,3,5,7]: print p
n,o = 11,0
t = []
l = len(w)
p = n
heappush(t, (p*p, n,o,p))
print p
while True:
n,o = n+w[o],(o+1)%l
p = n
if not t[0][0] <= p:
heappush(t, (p*p, n,o,p))
print p
continue
while t[0][0] <= p:
_, b,c,d = t[0]
b,c = b+w[c],(c+1)%l
heapreplace(t, (b*d, b,c,d))
sieve()

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