Efficient Prime Number Generating Algorithms
Efficient Prime Number Generating Algorithms
pp=2
ps=[pp]
lim=raw_input("\nGenerate prime numbers up to what number? : ")
while pp<int(lim):
pp+=1
test=True
for a in ps:
if pp%a==0: test=False
if test: ps.append(pp)
return ps
Note: The code given above does not constitute a complete program. See Appendix A for a complete program
including a user interface.
Such a rudimentary algorithm takes a strictly brute force approach to effectively achieve the goal of identifying each
prime number and storing it in an array. I am sure you would agree that this is also about the least efficient means of
generating prime numbers.
Runtime Data
primes pgsimple1
up to takes
These are the best time results taken from 5 test runs at each limit.
This table records the runtimes for pgsimple1 up to each limit indicated. Please accept that these runtimes and all of
the runtimes given throughout this document may differ somewhat from those which you may get running the same
program on a computer with different hardware or software as mine, which has an AMD Turion 64 1.9GHz with
2GB RAM, 160GB HDD and Windows Vista.
Efficient Prime Number Generating Algorithms 2
PGsimple2
A first step at improving this algorithm might be efficiently selecting potential primes. It is most common to see such
a device in algorithms which start with the integer 3 and proceed by selecting successive potential primes through
the odd integers only. This reduces by half the total number of potential primes which must be tested.
pp=2
ps=[pp]
pp+=1
ps.append(pp)
lim=raw_input("\nGenerate prime numbers up to what number? : ")
while pp<int(lim):
pp+=2
test=True
for a in ps:
if pp%a==0: test=False
if test: ps.append(pp)
return ps
Now, brute force has been augmented by some simple logic to significantly improve efficiency, reducing the number
of potential primes by half.
Runtime Data
100 0.0 ~
1000 .01400 2.00
10000 .85700 1.98
100000 65.240 2.00
1000000 5392.9 1.99
10000000 458123 ~
These are the best time results taken from 5 test runs at each limit.
This table records the runtimes for pgsimple2 and how many times faster it completes the run up to each limit
compared to pgsimple1. Note that the efficiency remains close to double that of pgsimple1 at any limit. Even at this
speed, it is still quite impractical to generate 8 digit primes or more. But, I did it just to see how long it would take.
PGsimple3
The next most obvious improvement would probably be limiting the testing process to only checking if the potential
prime can be factored by those primes less than or equal to the square root of the potential prime, since primes larger
than the square root of the potential prime will be complimentary factors of at least one prime less than the square
root of the potential prime.
pp=2
ps=[pp]
pp+=1
ps.append(pp)
lim=raw_input("\nGenerate prime numbers up to what number? : ")
while pp<int(lim):
Efficient Prime Number Generating Algorithms 3
pp+=2
test=True
sqrtpp=sqrt(pp)
for a in ps:
if a>sqrtpp: break
if pp%a==0: test=False
if test: ps.append(pp)
return ps
Runtime Data
100 0.0 ~ ~
1000 .00300 9.33 4.67
10000 .06200 27.4 13.8
100000 1.1220 116 58.1
1000000 26.979 398 200
10000000 705.37 ~ 649
100000000 18780 ~ ~
These are the best time results taken from 5 test runs at each limit.
This table records the runtimes for pgsimple3 and how many times faster it completes the run up to each limit
compared to pgsimple1 and pgsimple2. Note that the longer the program is run, the more significant the efficiency
becomes.
This algorithm makes truly significant strides in efficiency and, at this point, most programmers have exhausted their
ability or desire to continue improving the efficiency of the prime number generator, but we shall go on.
PGsimple4
Recognizing that by using a skip number of 2 to select only odd potential primes, it is no longer necessary to test
potential primes against all the primes less than the square root of the prime, as none of them can be factored by 2.
Therefore, we can remove the first prime number from the set of primes which we test potential primes against. This
requires dividing the prime set (ps) array into excepted prime (ep) and test prime (tp) arrays, then recombining them
at the end to send the complete set back to the function call.
pp=2
ep=[pp]
pp+=1
tp=[pp]
ss=[2]
lim=raw_input("\nGenerate prime numbers up to what number? : ")
while pp<int(lim):
pp+=ss[0]
test=True
sqrtpp=sqrt(pp)
for a in tp:
Efficient Prime Number Generating Algorithms 4
if a>sqrtpp: break
if pp%a==0: test=False
if test: tp.append(pp)
ep.reverse()
[tp.insert(0,a) for a in ep]
return tp
In the next version it will be shown why we put the skip number (2) into a skip set (ss) array.
Runtime Data
100 0.0 ~
1000 .00300 1.00
10000 .05200 1.19
100000 1.1140 1.01
1000000 26.734 1.01
10000000 702.54 1.00
100000000 18766 1.00
These are the best time results taken from 5 test runs at each limit.
This table records the runtimes for pgsimple4 and how many times faster it completes the run up to each limit
compared to pgsimple3.
What improvement in efficiency? Note that there is only a marginal increase in efficiency compared to pgsimple3.
Worry not, increases in efficiency multiply as more primes are eliminated from the testing process in the more
advanced version of the program which I will show you next.
PG7.8
This algorithm efficiently selects potential primes by eliminating multiples of previously identified primes from
consideration and minimizes the number of tests which must be performed to verify the primacy of each potential
prime. While the efficiency of selecting potential primes allows the program to sift through a greater range of
numbers per second the longer the program is run, the number of tests which need to be performed on each potential
prime does continue to rise, (but rises at a slower rate compared to other algorithms). Together, these processes bring
greater efficiency to generating prime numbers, making the generation of even 10 digit verified primes possible
within a reasonable amount of time on a PC.
Further skip sets can be developed to eliminate the selection of potential primes which can be factored by each prime
that has already been identified. Although this process is more complex, it can be generalized and made somewhat
elegant. At the same time, we can continue to eliminate from the set of test primes each of the primes which the skip
sets eliminate multiples of, minimizing the number of tests which must be performed on each potential prime. This
example is fully commented, line by line, with some explanation to help the reader fully comprehend how the
algorithm works. A complete program including a user interface, but without the comments, can be found in
Appendix B.
Please disregard syntactical errors which occur in the user interface such as “the 1th prime”, instead of “1st”, and the
inclusion of the last prime generated in the completed array even though it may be larger than the user defined limit.
These errors can easily be corrected at the convenience of the student programmer, but were not necessary to
illustrate the performance of the algorithms. I apologize for any confusion or inconvenience this may have caused
the reader.
Efficient Prime Number Generating Algorithms 5
""" Loop until the construction of the new skip set has gone
through the range of the new
skip set. """
for n in ss:
""" Loop through the current skip set array. """
npp=pp+n
""" Assign the next potential prime the value of the
potential prime plus
the value of the current member of the skip set. """
if npp>int(lim): break
""" If the next potential prime is greater than the
user defined limit,
then end the 'for n' loop. """
sqrtnpp=sqrt(npp)
""" Get the square root of the next potential prime,
which will be the
limit for the verification process. """
test=True
""" Set the verification flag to True. """
for q in tp:
""" Loop through the array of the primes necessary
for verification of the
next potential prime. """
if sqrtnpp<q: break
""" If the test prime is greater than the
square root of the next
potential prime, then end testing through the
'for q' loop. """
elif npp%q==0:
""" If the test prime IS a factor of the next
potential prime. """
test=False
""" Then set the verification flag to
False since the next
potential prime is not a prime number.
"""
break
""" And end testing through the 'for q'
loop. """
""" Otherwise, continue testing through the
'for q' loop. """
if test:
""" If the next potential prime has been verified as
a prime number. """
if npp<=sqrtlim: tp.append(npp)
""" And if the next potential prime is less
than or equal to the
Efficient Prime Number Generating Algorithms 10
Runtime Data
100 0.0 ~ ~
1000 .00100 28.0 3.00
10000 .01800 94.3 2.89
100000 .28400 459 3.92
1000000 5.6220 1909 4.76
10000000 120.53 ~ 5.83
100000000 2752.1 ~ 6.82
1000000000 65786 ~ ~
These are the best time results taken from 5 test runs at each limit.
Efficient Prime Number Generating Algorithms 12
This table records the runtimes for pg7.8 and how many times faster it completes the run up to each limit compared
to pgsimple1 and pgsimple4. Note that again the longer the program is run, the more significant the efficiency
becomes.
Appendix A
#! /usr/bin/env python
from math import sqrt
from time import time
def pg():
# pgsimple1, the least efficient algorithm
lim=raw_input("\nGenerate prime numbers up to what number? : ")
pp=2
ps=[pp]
bt=time()
while pp<int(lim):
pp+=1
test=True
for a in ps:
if pp%a==0: test=False
if test: ps.append(pp)
et=time()
tt=et-bt
a=test=et=bt=pp=0
print "\nIt took",tt,"seconds to generate the prime set up to:
",lim,"\nwith",len(ps),"members."
tt=lim=0
return ps
def ui(a):
m="\nDo you wish to review the numbers? Enter y for yes or q to
quit. "
n="From: "
o="To: "
p="or"
q="is out of the range of the set generated."
r="and"
s="There are none between"
t="\nPlease pick between 0"
u="\nThey are the"
v="th thru"
w="th members."
x="\nPlease choose a number that is less than"
y="a prime number."
Efficient Prime Number Generating Algorithms 13
z="\nThere are"
A="members of the prime set"
C="Make a selection or enter q to quit. "
f=raw_input(m)
while f!='q':
if f=='y':
print "\nChoose a category:"
print "a) Pick a range of indexes of members of the
prime number set."
print "b) Pick a range of numbers to view prime
numbers in that range."
print "d) Input a number to check its membership in
the prime number set."
print "e) Get the number of members in the prime set
up to a particular number."
print "f) Get the number of members in the prime set
between a range of numbers."
print "v) View 100 primes at a time."
f=raw_input(C)
if f=='a':
print t,r,len(a)
f=raw_input(n)
g=raw_input(o)
if int(g)<int(f):
h=f
f=g
g=h
if int(f)<0 or int(g)>len(a): print f,p,g,q
elif f==g: print s,f,r,g
else: print [a[h] for h in
range(int(f),int(g))],"\n",u,str(int(f)+1)+v,str(g)+w
if f=='b':
print t,r,a[len(a)-1]+1
f=raw_input(n)
g=raw_input(o)
if int(g)<int(f):
h=f
f=g
g=h
if int(f)<0 or int(g)>a[len(a)-1]+1: print f,p,g,q
elif f==g: print s,f,r,g
else:
i=0
while a[i]<int(f): i+=1
j=i
while i<len(a) and a[i]<=int(g):
print a[i],
Efficient Prime Number Generating Algorithms 14
i+=1
print u,str(int(j)+1)+v,str(i)+w
if f=='d':
print x,a[len(a)-1]+1
f=raw_input("What number do you want to check?
")
for g in a:
if int(g)==int(f): print f,"is",y
if int(g)>int(f): print f,"is not",y
if int(f)<0 or int(g)>=int(f): break
if int(f)>g+1 or int(f)<0: print f,q
if f=='e':
print x,a[len(a)-1]+2
f=raw_input(o)
if -1<int(f)<a[len(a)-1]+2:
g=0
while a[g]<=int(f):
g+=1
if g==len(a): break
print z,g,A,"up to",f
else: print f,q
if f=='f':
print t,r,a[len(a)-1]+1
f=raw_input(n)
g=raw_input(o)
if int(g)<int(f):
h=f
f=g
g=h
i=0
if int(f)<0 or int(g)>a[len(a)-1]+1: print f,p,g,q
elif f==g: print s,f,r,g
else:
for j in a:
if int(f)<=int(j)<=int(g): i+= 1
elif int(j)>int(g): break
print z,i,A,"from",f, "thru",g
if f=='v':
g=0
h=1
while f!='q' and g<len(a):
i=h*100
for g in range(100*(h-1),i):
if g==len(a):
i=len(a)
break
print a[g],
Efficient Prime Number Generating Algorithms 15
print u,str(100*(h-1)+1)+v,str(i)+w
h+=1
if g==len(a): break
f=raw_input("\nView the next 100 members
or enter q to quit. ")
f=raw_input(m)
def run(a='r'):
while a is 'r':
a=raw_input("\nEnter r to run prime generator. ")
if a!='r': return
b=pg()
ui(b)
if __name__ == "__main__":
run()
print "\n"*5,"Don't go away mad...Just go away.","\n"*5
raw_input()
Appendix B
#! /usr/bin/env python
from math import sqrt
from time import time
def pg():
lim=raw_input("\nGenerate prime numbers up to what number? : ")
sqrtlim=sqrt(float(lim))
pp=2
ep=[pp]
ss=[pp]
pp+=1
i=0
rss=[ss[0]]
tp=[pp]
xp=[]
pp+=ss[0]
npp=pp
tp.append(npp)
rss.append(rss[i]*tp[0])
bt=time()
while npp<int(lim):
i+=1
while npp<rss[i]+1:
for n in ss:
npp=pp+n
if npp>int(lim): break
if npp<=rss[i]+1: pp=npp
sqrtnpp=sqrt(npp)
test=True
for q in tp:
Efficient Prime Number Generating Algorithms 16
if sqrtnpp<q: break
elif npp%q==0:
test=False
break
if test:
if npp<=sqrtlim: tp.append(npp)
else: xp.append(npp)
if npp>int(lim): break
if npp>int(lim): break
lrpp=pp
nss=[]
while pp<(rss[i]+1)*2-1:
for n in ss:
npp=pp+n
if npp>int(lim): break
sqrtnpp=sqrt(npp)
test=True
for q in tp:
if sqrtnpp<q: break
elif npp%q==0:
test=False
break
if test:
if npp<=sqrtlim: tp.append(npp)
else: xp.append(npp)
if npp%tp[0]!=0:
nss.append(npp-lrpp)
lrpp=npp
pp=npp
if npp>int(lim): break
if npp>int(lim): break
ss=nss
ep.append(tp[0])
del tp[0]
rss.append(rss[i]*tp[0])
npp=lrpp
et=time()
i=nss=npp=n=sqrtnpp=test=q=r=lrpp=rss=ss=pp=sqrtlim=0
tt=et-bt
ep.reverse()
[tp.insert(0,a) for a in ep]
tp.reverse()
[xp.insert(0,a) for a in tp]
print "\nIt took",tt,"seconds to generate the prime set up to:
",lim,"\nwith",len(xp),"members."
et=bt=ep=tp=a=tt=lim=0
return xp
Efficient Prime Number Generating Algorithms 17
def ui(a):
m="\nDo you wish to review the numbers? Enter y for yes or q to
quit. "
n="From: "
o="To: "
p="or"
q="is out of the range of the set generated."
r="and"
s="There are none between"
t="\nPlease pick between 0"
u="\nThey are the"
v="th thru"
w="th members."
x="\nPlease choose a number that is less than"
y="a prime number."
z="\nThere are"
A="members of the prime set"
C="Make a selection or enter q to quit. "
f=raw_input(m)
while f!='q':
if f=='y':
print "\nChoose a category:"
print "a) Pick a range of indexes of members of the
prime number set."
print "b) Pick a range of numbers to view prime
numbers in that range."
print "d) Input a number to check its membership in
the prime number set."
print "e) Get the number of members in the prime set
up to a particular number."
print "f) Get the number of members in the prime set
between a range of numbers."
print "v) View 100 primes at a time."
f=raw_input(C)
if f=='a':
print t,r,len(a)
f=raw_input(n)
g=raw_input(o)
if int(g)<int(f):
h=f
f=g
g=h
if int(f)<0 or int(g)>len(a): print f,p,g,q
elif f==g: print s,f,r,g
else: print [a[h] for h in
range(int(f),int(g))],"\n",u,str(int(f)+1)+v,str(g)+w
if f=='b':
Efficient Prime Number Generating Algorithms 18
print t,r,a[len(a)-1]+1
f=raw_input(n)
g=raw_input(o)
if int(g)<int(f):
h=f
f=g
g=h
if int(f)<0 or int(g)>a[len(a)-1]+1: print f,p,g,q
elif f==g: print s,f,r,g
else:
i=0
while a[i]<int(f): i+=1
j=i
while i<len(a) and a[i]<=int(g):
print a[i],
i+=1
print u,str(int(j)+1)+v,str(i)+w
if f=='d':
print x,a[len(a)-1]+1
f=raw_input("What number do you want to check?
")
for g in a:
if int(g)==int(f): print f,"is",y
if int(g)>int(f): print f,"is not",y
if int(f)<0 or int(g)>=int(f): break
if int(f)>g+1 or int(f)<0: print f,q
if f=='e':
print x,a[len(a)-1]+2
f=raw_input(o)
if -1<int(f)<a[len(a)-1]+2:
g=0
while a[g]<=int(f):
g+=1
if g==len(a): break
print z,g,A,"up to",f
else: print f,q
if f=='f':
print t,r,a[len(a)-1]+1
f=raw_input(n)
g=raw_input(o)
if int(g)<int(f):
h=f
f=g
g=h
i=0
if int(f)<0 or int(g)>a[len(a)-1]+1: print f,p,g,q
elif f==g: print s,f,r,g
Efficient Prime Number Generating Algorithms 19
else:
for j in a:
if int(f)<=int(j)<=int(g): i+= 1
elif int(j)>int(g): break
print z,i,A,"from",f, "thru",g
if f=='v':
g=0
h=1
while f!='q' and g<len(a):
i=h*100
for g in range(100*(h-1),i):
if g==len(a):
i=len(a)
break
print a[g],
print u,str(100*(h-1)+1)+v,str(i)+w
h+=1
if g==len(a): break
f=raw_input("\nView the next 100 members
or enter q to quit. ")
f=raw_input(m)
def run(a='r'):
while a is 'r':
a=raw_input("\nEnter r to run prime generator. ")
if a!='r': return
b=pg()
ui(b)
if __name__ == "__main__":
run()
print "\n"*5,"Don't go away mad...Just go away.","\n"*5
raw_input()
Article Sources and Contributors 20
License
Creative Commons Attribution-Share Alike 3.0 Unported
http:/ / creativecommons. org/ licenses/ by-sa/ 3. 0/