9.6. 1 2 3 4 # # # # 5 6 7 202 PRIME GENERATION WITH A LIST Count the number of prime numbers less than 2 million and time how long it takes Compares the performance of two different algorithms. from from time math import import clock sqrt 8 9 10 def 11 12 13 count_primes(n): ''' Generates all the prime numbers from 2 to n - 1. 14 n ''' start 15 1 = is the clock() largest potential prime considered. # Record start time 16 17 count = 0 for val in range(2, n): result = True # Provisionally, n is prime root = int(sqrt(val) + 1) # Try all potential factors from 2 to the square root of n trial_factor = 2 while result and trial_factor <= root: result = (val % trial_factor != 0 ) # Is it a factor? trial_factor += 1 # Try next candidate if result: count += 1 18 19 20 21 22 23 24 25 26 27 28 29 stop = clock() print("Count =", 30 count, # Stop "Elapsed the clock time:", stop - start, "seconds") 31 32 33 34 def 35 36 37 38 39 40 seive(n): ''' Generates all the prime numbers from 2 to n - 1. n - 1 Algorithm ''' is the largest potential originally developed by prime considered. Eratosthenes. 41 42 43 44 45 46 47 48 start = clock() # Record start time # Each position in the Boolean list indicates # if the number of that position is not prime: # false means "prime," and true means "composite." # Initially all numbers are prime until proven otherwise nonprimes = # Global list initialized to all * [False] n False 49 50 count = 0 51 52 53 54 # First prime number is 2; 0 and prime nonprimes[0] = nonprimes[1] = True 1 are not 55 # Start at the first prime number, 2. Draft date: November 13, 2011 ©2011 Richard L. Halterman 9.7. 203 SUMMARY for i # prime if 56 57 58 59 in range(2, n): See if i is not nonprimes[i]: count += prime, 1 # It is so eliminate all of # multiples that cannot be prime for j in range(2 *i, n, i): nonprimes[j] = True Print the elapsed time 60 61 62 63 64 # stop = clock() print("Count =", 65 66 count, "Elapsed time:", stop its - start, "seconds") 67 68 69 def main(): count_primes(2000000) seive(2000000) 70 71 72 73 main() Since printing to the screen takes up the majority of the time, Listing 9.20 (timeprimes.py) counts the number of primes rather than printing each one. This allows us to better compare the behavior of the two approaches. The square root version has been optimized slightly more: the floating-point root variable is not an integer. The less than comparison between two integers is faster than the floating-point equivalent. The output of Listing 9.20 (timeprimes.py) on one system reveals Count = 148932 Elapsed time: 56.446094827055276 seconds Count = 148933 Elapsed time: 0.8864909583615557 seconds Our previous version requires almost a minute (56 seconds) to count the number of primes less than two million, while the version based on the Sieve of Eratosthenes takes less than one second. The Sieve version is over 60 times faster than the optimized square root version. 9.7 Summary • A list represents an ordered sequence of objects • An element in a list may be accessed via its index using []. The first element is at index 0. If the list contains n elements, the index of the last element is n 1. • A positive list index is an offset from the beginning of the list. A negative list index is an offset back from an imaginary element one past the end of the list. • A list may elements of different types. • List literals list their elements in a comma-separated list enclosed within square brackets ([]). • The len function returns the length of the list • A list index is sometimes called a subscript. ©2011 Richard L. Halterman Draft date: November 13, 2011