Prime factorization - list - python

I am trying to implement a function primeFac() that takes as input a positive integer n and returns a list containing all the numbers in the prime factorization of n.
I have gotten this far but I think it would be better to use recursion here, not sure how to create a recursive code here, what would be the base case? to start with.
My code:
def primes(n):
primfac = []
d = 2
while (n > 1):
if n%d==0:
primfac.append(d)
# how do I continue from here... ?

A simple trial division:
def primes(n):
primfac = []
d = 2
while d*d <= n:
while (n % d) == 0:
primfac.append(d) # supposing you want multiple factors repeated
n //= d
d += 1
if n > 1:
primfac.append(n)
return primfac
with O(sqrt(n)) complexity (worst case). You can easily improve it by special-casing 2 and looping only over odd d (or special-casing more small primes and looping over fewer possible divisors).

The primefac module does factorizations with all the fancy techniques mathematicians have developed over the centuries:
#!python
import primefac
import sys
n = int( sys.argv[1] )
factors = list( primefac.primefac(n) )
print '\n'.join(map(str, factors))

This is a comprehension based solution, it might be the closest you can get to a recursive solution in Python while being possible to use for large numbers.
You can get proper divisors with one line:
divisors = [ d for d in xrange(2,int(math.sqrt(n))) if n % d == 0 ]
then we can test for a number in divisors to be prime:
def isprime(d): return all( d % od != 0 for od in divisors if od != d )
which tests that no other divisors divides d.
Then we can filter prime divisors:
prime_divisors = [ d for d in divisors if isprime(d) ]
Of course, it can be combined in a single function:
def primes(n):
divisors = [ d for d in range(2,n//2+1) if n % d == 0 ]
return [ d for d in divisors if \
all( d % od != 0 for od in divisors if od != d ) ]
Here, the \ is there to break the line without messing with Python indentation.

I've tweaked #user448810's answer to use iterators from itertools (and python3.4, but it should be back-portable). The solution is about 15% faster.
import itertools
def factors(n):
f = 2
increments = itertools.chain([1,2,2], itertools.cycle([4,2,4,2,4,6,2,6]))
for incr in increments:
if f*f > n:
break
while n % f == 0:
yield f
n //= f
f += incr
if n > 1:
yield n
Note that this returns an iterable, not a list. Wrap it in list() if that's what you want.

Most of the above solutions appear somewhat incomplete. A prime factorization would repeat each prime factor of the number (e.g. 9 = [3 3]).
Also, the above solutions could be written as lazy functions for implementation convenience.
The use sieve Of Eratosthenes to find primes to test is optimal, but; the above implementation used more memory than necessary.
I'm not certain if/how "wheel factorization" would be superior to applying only prime factors, for division tests of n.
While these solution are indeed helpful, I'd suggest the following two functions -
Function-1 :
def primes(n):
if n < 2: return
yield 2
plist = [2]
for i in range(3,n):
test = True
for j in plist:
if j>n**0.5:
break
if i%j==0:
test = False
break
if test:
plist.append(i)
yield i
Function-2 :
def pfactors(n):
for p in primes(n):
while n%p==0:
yield p
n=n//p
if n==1: return
list(pfactors(99999))
[3, 3, 41, 271]
3*3*41*271
99999
list(pfactors(13290059))
[3119, 4261]
3119*4261
13290059

Here is my version of factorization by trial division, which incorporates the optimization of dividing only by two and the odd integers proposed by Daniel Fischer:
def factors(n):
f, fs = 3, []
while n % 2 == 0:
fs.append(2)
n /= 2
while f * f <= n:
while n % f == 0:
fs.append(f)
n /= f
f += 2
if n > 1: fs.append(n)
return fs
An improvement on trial division by two and the odd numbers is wheel factorization, which uses a cyclic set of gaps between potential primes to greatly reduce the number of trial divisions. Here we use a 2,3,5-wheel:
def factors(n):
gaps = [1,2,2,4,2,4,2,4,6,2,6]
length, cycle = 11, 3
f, fs, nxt = 2, [], 0
while f * f <= n:
while n % f == 0:
fs.append(f)
n /= f
f += gaps[nxt]
nxt += 1
if nxt == length:
nxt = cycle
if n > 1: fs.append(n)
return fs
Thus, print factors(13290059) will output [3119, 4261]. Factoring wheels have the same O(sqrt(n)) time complexity as normal trial division, but will be two or three times faster in practice.
I've done a lot of work with prime numbers at my blog. Please feel free to visit and study.

def get_prime_factors(number):
"""
Return prime factor list for a given number
number - an integer number
Example: get_prime_factors(8) --> [2, 2, 2].
"""
if number == 1:
return []
# We have to begin with 2 instead of 1 or 0
# to avoid the calls infinite or the division by 0
for i in xrange(2, number):
# Get remainder and quotient
rd, qt = divmod(number, i)
if not qt: # if equal to zero
return [i] + get_prime_factors(rd)
return [number]

Most of the answer are making things too complex. We can do this
def prime_factors(n):
num = []
#add 2 to list or prime factors and remove all even numbers(like sieve of ertosthenes)
while(n%2 == 0):
num.append(2)
n /= 2
#divide by odd numbers and remove all of their multiples increment by 2 if no perfectlly devides add it
for i in xrange(3, int(sqrt(n))+1, 2):
while (n%i == 0):
num.append(i)
n /= i
#if no is > 2 i.e no is a prime number that is only divisible by itself add it
if n>2:
num.append(n)
print (num)
Algorithm from GeeksforGeeks

prime factors of a number:
def primefactors(x):
factorlist=[]
loop=2
while loop<=x:
if x%loop==0:
x//=loop
factorlist.append(loop)
else:
loop+=1
return factorlist
x = int(input())
alist=primefactors(x)
print(alist)
You'll get the list.
If you want to get the pairs of prime factors of a number try this:
http://pythonplanet.blogspot.in/2015/09/list-of-all-unique-pairs-of-prime.html

def factorize(n):
for f in range(2,n//2+1):
while n%f == 0:
n //= f
yield f
It's slow but dead simple. If you want to create a command-line utility, you could do:
import sys
[print(i) for i in factorize(int(sys.argv[1]))]

Here is an efficient way to accomplish what you need:
def prime_factors(n):
l = []
if n < 2: return l
if n&1==0:
l.append(2)
while n&1==0: n>>=1
i = 3
m = int(math.sqrt(n))+1
while i < m:
if n%i==0:
l.append(i)
while n%i==0: n//=i
i+= 2
m = int(math.sqrt(n))+1
if n>2: l.append(n)
return l
prime_factors(198765430488765430290) = [2, 3, 5, 7, 11, 13, 19, 23, 3607, 3803, 52579]

You can use sieve Of Eratosthenes to generate all the primes up to (n/2) + 1 and then use a list comprehension to get all the prime factors:
def rwh_primes2(n):
# http://stackoverflow.com/questions/2068372/fastest-way-to-list-all-primes-below-n-in-python/3035188#3035188
""" Input n>=6, Returns a list of primes, 2 <= p < n """
correction = (n%6>1)
n = {0:n,1:n-1,2:n+4,3:n+3,4:n+2,5:n+1}[n%6]
sieve = [True] * (n/3)
sieve[0] = False
for i in xrange(int(n**0.5)/3+1):
if sieve[i]:
k=3*i+1|1
sieve[ ((k*k)/3) ::2*k]=[False]*((n/6-(k*k)/6-1)/k+1)
sieve[(k*k+4*k-2*k*(i&1))/3::2*k]=[False]*((n/6-(k*k+4*k-2*k*(i&1))/6-1)/k+1)
return [2,3] + [3*i+1|1 for i in xrange(1,n/3-correction) if sieve[i]]
def primeFacs(n):
primes = rwh_primes2((n/2)+1)
return [x for x in primes if n%x == 0]
print primeFacs(99999)
#[3, 41, 271]

from sets import Set
# this function generates all the possible factors of a required number x
def factors_mult(X):
L = []
[L.append(i) for i in range(2,X) if X % i == 0]
return L
# this function generates list containing prime numbers upto the required number x
def prime_range(X):
l = [2]
for i in range(3,X+1):
for j in range(2,i):
if i % j == 0:
break
else:
l.append(i)
return l
# This function computes the intersection of the two lists by invoking Set from the sets module
def prime_factors(X):
y = Set(prime_range(X))
z = Set(factors_mult(X))
k = list(y & z)
k = sorted(k)
print "The prime factors of " + str(X) + " is ", k
# for eg
prime_factors(356)

Simple way to get the desired solution
def Factor(n):
d = 2
factors = []
while n >= d*d:
if n % d == 0:
n//=d
# print(d,end = " ")
factors.append(d)
else:
d = d+1
if n>1:
# print(int(n))
factors.append(n)
return factors

This is the code I made. It works fine for numbers with small primes, but it takes a while for numbers with primes in the millions.
def pfactor(num):
div = 2
pflist = []
while div <= num:
if num % div == 0:
pflist.append(div)
num /= div
else:
div += 1
# The stuff afterwards is just to convert the list of primes into an expression
pfex = ''
for item in list(set(pflist)):
pfex += str(item) + '^' + str(pflist.count(item)) + ' * '
pfex = pfex[0:-3]
return pfex

I would like to share my code for finding the prime factors of number given input by the user:
a = int(input("Enter a number: "))
def prime(a):
b = list()
i = 1
while i<=a:
if a%i ==0 and i!=1 and i!=a:
b.append(i)
i+=1
return b
c = list()
for x in prime(a):
if len(prime(x)) == 0:
c.append(x)
print(c)

def prime_factors(num, dd=2):
while dd <= num and num>1:
if num % dd == 0:
num //= dd
yield dd
dd +=1
Lot of answers above fail on small primes, e.g. 3, 5 and 7. The above is succinct and fast enough for ordinary use.
print list(prime_factors(3))
[3]

Related

Algorithm of finding numbers

Write a recursive algorithm which enumerates dominant primes. Your algorithm should print dominant primes as it finds them (rather than at the end).By default we limit the dominant primes we are looking for to a maximum value of 10^12, the expected run time should be around or less than a minute.
The following is my python code which doesn't work as expected:
import math
def test_prime(n):
k = 2
maxk = int(math.sqrt(n))
while k <= maxk:
if n % k == 0:
return False
if k == 2:
k += 1
else:
k += 2
return (n is not 1)
def dominant_prime_finder(maxprime=10**12,n=1):
l = 1 #length of the current number
while n // 10 > 0:
l += 1
n //= 10
if test_prime(n) == True:
is_dominant_prime = True
index_smaller = n
while l > 1 and index_smaller > 9:
index_smaller //= 10
if test_prime(index_smaller) == False:
is_dominant_prime = False
break
for i in range(1,10):
if test_prime(i*10**l + n) == True:
is_dominant_prime = False
break
if is_dominant_prime == True:
print(n)
while n <= maxprime:
dominant_prime_finder()
You can solve the problem without enumerating all the numbers under 10^12 which is inefficient by doing a recursion on the length of the number.
It works the following way:
The prime number of length 1 are: 2,3,5,7.
For all these numbers check the third condition, for any digit dn+1∈{1,…,9} , dn+1dn…d0 is not prime. For 2 it's okay. For 3 it fails (13 for instance). Store all the prime you find in a list L. Do this for all the prime of length 1.
In L you now have all the prime number of length 2 with a prime as first digit, thus you have all the candidates for dominant prime of length 2
Doing this recursively gets you all the dominant prime, in python:
def test_prime(n):
k = 2
maxk = int(math.sqrt(n))
while k <= maxk:
if n % k == 0:
return False
if k == 2:
k += 1
else:
k += 2
return (n is not 1)
def check_add_digit(number,length):
res = []
for i in range(1,10):
if test_prime( i*10**(length) + number ):
res.append(i*10**(length) + number)
return res
def one_step(list_prime,length):
## Under 10^12
if length > 12:
return None
for prime in list_prime:
res = check_add_digit(prime,length)
if len(res) == 0:
#We have a dominant prime stop
print(prime)
else:
#We do not have a dominant prime but a list of candidates for length +1
one_step(res,length+1)
one_step([2,3,5,7], length=1)
This works in under a minute on my machine.
Well, there are several issues with this code:
You modify the original n at the beginning (n //= 10). This basically causes n to always be one digit. Use another variable instead:
m = n
while m // 10 > 0:
l += 1
m //= 10
Your recursive call doesn't update n, so you enter an infinite loop:
while n <= maxprime:
dominant_prime_finder()
Replace with:
if n <= maxprime:
dominant_prime_finder(maxprime, n + 1)
Even after fixing these issues, you'll cause a stack overflow simply because the dominant prime numbers are very far apart (2, 5, 3733, 59399...). So instead of using a recursive approach, use, for example, a generator:
def dominant_prime_finder(n=1):
while True:
l = 1 #length of the current number
m = n
while m // 10 > 0:
l += 1
m //= 10
if test_prime(n):
is_dominant_prime = True
index_smaller = n
while l > 1 and index_smaller > 9:
index_smaller //= 10
if not test_prime(index_smaller):
is_dominant_prime = False
break
for i in range(1,10):
if test_prime(i*10**l + n):
is_dominant_prime = False
break
if is_dominant_prime:
yield n
n = n + 1
g = dominant_prime_finder()
for i in range(1, 10): # find first 10 dominant primes
print(g.next())
This problem is cool. Here's how we can elaborate the recurrence:
def dominant_prime_finder(maxprime=10**12):
def f(n):
if n > maxprime:
return
is_dominant = True
power = 10**(math.floor(math.log(n, 10)) + 1)
for d in xrange(1, 10):
candidate = d * power + n
if test_prime(candidate):
f(candidate)
is_dominant = False
if is_dominant:
print int(n)
for i in [2,3,5,7]:
f(i)

Python: isPrime function much slower after adding lookup of pregenerated list?

I am solving Project Euler problems with Python. I have seen some solvers use isPrime() functions that simply test whether x % y == 0 for all y from 2 to x ** 0.5. That is not efficient and I want to write a better isPrime() function, based on the num % 30 test. This is what I came up with:
primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
primality = [1, 7, 11, 13, 17, 19, 23, 29]
def isPrime(num):
if not type(num) in (int, long):
raise ValueError
if num in primes:
return True
elif num < 2:
return False
elif num % 30 not in primality:
return False
else:
for prime in primes[3:]:
if num % prime == 0:
return False
seed, sqrt, tryfactor = 1, getIntSquareRoot(num), 1
while tryfactor < sqrt:
for trymod in primality:
tryfactor = seed * 30 + trymod
if num % tryfactor == 0 and not(num == tryfactor):
return False
seed += 1
return True
Problem 7 is to find the 10001st prime. So I decided to make the code append all these primes to a list which subsequent problems can refer to. I thought that given a 5-digit number num, num in primes would be a much faster operation that repeated num % tryfactor. For parameters where primes[-1] < num < (primes[-1] ** 0.2) it should still be faster to get tryfactor values from the list than repeatedly generating them through tryfactor = seed * 30 + trymod.
So I came up with the following:
def problem7():
count, seed = len(primes), 1
while True:
for modulus in primality:
num = seed * 30 + modulus
if isPrime(num):
count += 1
primes.append(num)
if count > 10000:
return num
seed += 1
def isPrimeB(num):
if not type(num) in (int, long):
raise ValueError
if num in primes:
return True
elif num < 2:
return False
elif num % 30 not in primality:
return False
else:
for prime in primes[3:]:
if num % prime == 0:
return False
seed, sqrt, tryfactor = 1, getIntSquareRoot(num), 1
while tryfactor < sqrt:
for trymod in primality:
tryfactor = seed * 30 + trymod
if num % tryfactor == 0 and not(num == tryfactor):
return False
seed += 1
return True
Of course I expect the code for problem 7 to be much slower, because generating the list of primes a few seconds. I also expect the code for later problems calling isPrime() (such as 10, 27, 35, 41 and 58) to run much faster.
However, I got a shock when the code for problems 27, 35, 41 and 58 became much slower. Could someone explain why looking up values in a list is much slower than calculating them? Or is there a mistake in my code? What else can I do to make the isPrime() function more efficient?
The reason it is slower is because the list lookup is O(n). Instead of using lists use sets:
primes = set()
primes.add(num)
The num in primes check will be now O(1).
Also forget about this "optimization": primes[3:]. It actually slows down your code, since it recreates the list (note that it won't work anyway if you switch to sets).
Finally you can implement the Sieve of Eratosthenes (although there are more sophisticated sieves) to generate primes fast.
#Freakish answered your question about why isPrimeB is slow. Let me propose a couple of alternatives to what you have written.
Here is my version of primality checking with a 2,3,5-wheel, which is the same algorithm as your isPrime function but stated rather differently:
def isPrime(n):
d, w, wheel = 2, 0, [1,2,2,4,2,4,2,4,6,2,6]
while d*d <= n:
if n%d == 0: return False
d = d + wheel[w]
w = 3 if w == 10 else w+1
return True
There are a couple of ways to compute the nth prime. One way uses a Sieve of Eratosthenes. Number theory tells us that the nth prime is always less than n(log n + log log n) with logarithms to base e, so you could sieve up to the limit and discard the excess primes. Here's the sieve:
def primes(n):
m = (n-1)//2; b = [True] * m
i, p, ps = 0, 3, [2]
while i < m:
if b[i]:
ps.append(p)
for j in range(2*i*i+6*i+3, m, p):
b[j] = False
i, p = i+1, p+2
return ps
So, to get the 10001st prime:
>>> 10000 * ( log(10000) + log(log(10000)) )
114306.67178344031
>>> (primes(114306))[10000]
104743
Another alternative generates candidate primes using a 2,3,5,7-wheel and confirms their primality by a Miller-Rabin test to the three bases 2, 7, 61, which is sufficient for primes less then 2^32 (actually, a little bit bigger):
def genPrimes(): # valid to 2^32
def isPrime(n):
def isSpsp(n, a):
d, s = n-1, 0
while d%2 == 0:
d /= 2; s += 1
t = pow(a,d,n)
if t == 1: return True
while s > 0:
if t == n-1: return True
t = (t*t) % n; s -= 1
return False
for p in [2, 7, 61]:
if n % p == 0: return n == p
if not isSpsp(n, p): return False
return True
w, wheel = 0, [1,2,2,4,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]
p = 2; yield p
while True:
p = p + wheel[w]
w = 4 if w == 51 else w + 1
if isPrime(p): yield p
Then the nth prime can be computed by the expression next(itertools.islice(genPrimes(), n, n+1)):
>>> next(itertools.islice(genPrimes(), 10000, 10001))
104743
Both methods return the 10001st prime instantly, as soon as you press the enter key.
If your interested in programming with prime numbers (or you just want to solve the prime number problems in Project Euler), you might be interested in this essay or in these entries at my blog.

Finding the greatest prime divisor (the fastest program possible)

I was checking the problems on http://projecteuler.net/
The third problem is as follows:
The prime factors of 13195 are 5, 7, 13 and 29. What is the largest
prime factor of the number 600851475143 ?
My solution code is below. But it is so slow that I think it will take weeks to complete.
How can I improve it? Or is Python itself too slow to solve this problem?
def IsPrime(num):
if num < 2:
return False
if num == 2:
return True
else:
for div in range(2,num):
if num % div == 0:
return False
return True
GetInput = int (input ("Enter the number: "))
PrimeDivisors = []
for i in range(GetInput, 1, -1):
print(i)
if GetInput % i == 0 and IsPrime(i) is True:
PrimeDivisors.append(i)
break
else:
continue
print(PrimeDivisors)
print("The greatest prime divisor is:", max(PrimeDivisors))
The problem with your solution is that you don't take your found prime factors into account, so you're needlessly checking factors after you've actually found the largest one. Here's my solution:
def largest_prime_factor(n):
largest = None
for i in range(2, n):
while n % i == 0:
largest = i
n //= i
if n == 1:
return largest
if n > 1:
return n
Project Euler problems are more about mathematics than programming, so if your solution is too slow, it's probably not your language that's at fault.
Note that my solution works quickly for this specific number by chance, so it's definitely not a general solution. Faster solutions are complicated and overkill in this specific case.
This might not be the fastest algorithm but it's quite efficient:
def prime(x):
if x in [0, 1]:
return False
for n in xrange(2, int(x ** 0.5 + 1)):
if x % n == 0:
return False
return True
def primes():
"""Prime Number Generator
Generator an infinite sequence of primes
http://stackoverflow.com/questions/567222/simple-prime-generator-in-python
"""
# Maps composites to primes witnessing their compositeness.
# This is memory efficient, as the sieve is not "run forward"
# indefinitely, but only as long as required by the current
# number being tested.
#
D = {}
# The running integer that's checked for primeness
q = 2
while True:
if q not in D:
# q is a new prime.
# Yield it and mark its first multiple that isn't
# already marked in previous iterations
#
yield q
D[q * q] = [q]
else:
# q is composite. D[q] is the list of primes that
# divide it. Since we've reached q, we no longer
# need it in the map, but we'll mark the next
# multiples of its witnesses to prepare for larger
# numbers
#
for p in D[q]:
D.setdefault(p + q, []).append(p)
del D[q]
q += 1
def primefactors(x):
if x in [0, 1]:
yield x
elif prime(x):
yield x
else:
for n in primes():
if x % n == 0:
yield n
break
for factor in primefactors(x // n):
yield factor
Usage:
>>> list(primefactors(100))
[2, 2, 5, 5]
My code which seems enough fast to me. Using collections.defaultdict() would make the code of primes() abit cleaner but I guess the code would loose some speed due to importing it.
def primes():
"""Prime number generator."""
n, skip = 2, {}
while True:
primes = skip.get(n)
if primes:
for p in primes:
skip.setdefault(n + p, set()).add(p)
del skip[n]
else:
yield n
skip[n * n] = {n}
n += 1
def un_factor(n):
"""Does an unique prime factorization on n.
Returns an ordered tuple of (prime, prime_powers)."""
if n == 1:
return ()
result = []
for p in primes():
(div, mod), power = divmod(n, p), 1
while mod == 0:
if div == 1:
result.append((p, power))
return tuple(result)
n = div
div, mod = divmod(n, p)
if mod != 0:
result.append((p, power))
power += 1
Test run:
>>> un_factor(13195)
((5, 1), (7, 1), (13, 1), (29, 1))
>>> un_factor(600851475143)
((71, 1), (839, 1), (1471, 1), (6857, 1))
>>> un_factor(20)
((2, 2), (5, 1))
EDIT: Minor edits for primes() generator based on this recipe.
EDIT2: Fixed for 20.
EDIT3: Replaced greatest_prime_divisor() with un_factor().
def getLargestFactor(n):
maxFactor = sqrt(n)
lastFactor = n
while n%2 == 0:
n /= 2
lastFactor = 2
for i in xrange(3,int(maxFactor),2 ):
if sqrt(n) < i:
return n
while n%i == 0 and n > 1:
n /= i
lastFactor = i
return lastFactor
This should be fairly efficient. Dividing each factor all out, this way we only find the prime factors. And using the fact that there can only be one prime factor of a number larger than sqrt(n).

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

Can this be made more pythonic?

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.

Categories

Resources