Computational discrete mathematics with Python
May 2, 2017 | Author: gxsteph | Category: N/A
Short Description
programming with Python...
Description
Computational discrete mathematics with Python Fred Richman Florida Atlantic University June 21, 2013
Contents 0 Python
2
1 Integers and strings 1.1 Decimal and other bases . . . . . . . . . . . . . . . . . . . . .
3 5
2 Prime numbers 2.1 The smallest prime factor . . . . 2.2 Using a for-statement . . . . . . 2.3 Testing the algorithm . . . . . . . 2.4 De…ning a function . . . . . . . . 2.5 Speeding the algorithm up . . . . 2.6 Goldbach’s conjecture . . . . . . 2.7 Sophie Germain primes . . . . . . 2.8 There are in…nitely many primes 2.9 Largest prime factor . . . . . . . 2.10 Complete factorization . . . . . . 2.11 More on recursive functions . . . 2.12 Working with lists . . . . . . . . 3 The 3.1 3.2 3.3
. . . . . . . . . . . .
7 7 9 10 10 11 12 14 16 19 20 21 23
Euclidean algorithm The Euler '-function . . . . . . . . . . . . . . . . . . . . . . . The extended Euclidean algorithm . . . . . . . . . . . . . . . Orders of units modulo n . . . . . . . . . . . . . . . . . . . . .
23 25 27 29
1
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
4 Sieving for primes 30 4.1 Counts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 5 Mersenne primes 34 5.1 The Lucas-Lehmer test . . . . . . . . . . . . . . . . . . . . . . 36 5.2 Repunits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 5.3 Emirps and palindromic primes . . . . . . . . . . . . . . . . . 37 6 Fermat’s theorem 37 6.1 Carmichael numbers . . . . . . . . . . . . . . . . . . . . . . . 39 6.2 The Miller-Rabin test . . . . . . . . . . . . . . . . . . . . . . . 40 7 The 7.1 7.2 7.3 7.4
sum of the squares of the digits of Happy numbers . . . . . . . . . . . . . Numbers whose digits increase . . . . . Unhappy numbers . . . . . . . . . . . . Changing exponents and bases . . . . .
a . . . .
number . . . . . . . . . . . . . . . . . . . . . . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
41 42 44 46 47
8 Finding orbits
48
9 Aliquot sequences
51
10 The Collatz function
51
11 Bulgarian solitaire
52
12 The digits of n-factorial 53 12.1 Benford’s law . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 13 Sequences of zeros in 2n
56
14 Ciphers
57
15 Stu¤
59
0
Python
You can’t do computational mathematics without writing programs. In this course, all of the programs are to be written in Python. There is a lot of 2
material on Python on the web. The particular version I’m going to use is Python 2.7.3. The …rst thing you need to do is to download Python 2.7.3. You can do this at http://www.python.org/getit/ After you have downloaded Python, open IDLE, the Python GUI (graphical user interface). This gives you an interactive window in which you can play with Python. The prompt line looks like >>> You can try various arithmetic operations …rst. If you type 2+7, and then “Enter”, you should see 9 >>> Try typing 2*7 and 2/7 and 2**7. The last one should give you 27 which is 128. Now try 2**100. The L at the end of the number means that it is a “long integer”. Now type range(10). You should get a list of the …rst ten numbers, starting with 0. Lists in Python are enclosed with square brackets, and the entries are separated by commas. Now try range(5,10) and range(-5,10). Try range(a,b) with various values of a and b until you understand how it works. Now type range(0,100,7) and range(-20,20,3). What do these look like? Try a few more. Exercise 1. Write down a description of what range(a,b) is for arbitrary integers a and b. Exercise 2. Write down a description of what range(a,b,c) is for arbitrary integers a, b, and c.
1
Integers and strings
We will be working mostly with the integers: :::
5; 4; 3; 2; 1; 0; 1; 2; 3; 4; 5; : : :
3
Your …rst project is to familiarize yourself with the Python operator %. Get into the Python interactive mode (shell or console). One way to do this is just to open IDLE from the start menu. You should see the prompt: >>> If you type 2+3, and then “Enter”, you should see 5 >>> If you type 100%17, and then “Enter”, you should see 15 >>> That’s because when you divide 100 by 17 you get a remainder of 15. That is, 100 = 5 17 + 15. I have no idea why they use the percent sign to indicate that function— the same thing is done in the language C. What happens when you type 100%-17 or -100%17 or -100%-17? If you type 100/17, and then “Enter”, you should see 5 >>> That’s because when you divide 100 by 17 you get a quotient of 5 (and a remainder of 15). So 100 is equal to (100/17)*17+(100%17). Type that last expression into Python, in the interactive mode, and press “Enter”. What do you get? Exercise 1. Come up with a description of a%b when a and b are arbitrary integers. Exercise 2. Describe b/a for arbitrary integers a and b. Exercise 3. Despite its name, the division algorithm is a mathematical theorem, not an algorithm. One way of stating it is: If a and b are integers, and a 6= 0, then b = qa + r for unique integers q and r, with 0 r < jaj. The integer q is called the quotient, and the integer r, the remainder. Your question is, what is the relationship between q and a/b, and between r and b%a? You can only …nd out by experimenting with Python. You are trying to describe how Python behaves. Experiment with both negative and positive values of a and b. 4
1.1
Decimal and other bases
When we write a number like 1776, we use the standard decimal notation. That is, we use ten digits, 0; 1; 2; 3; 4; 5; 6; 7; 8; 9, and their value depends on their position. The …rst occurrence of the digit 7 in the string of digits ‘1776’ stands for seven hundred; the second stands for seventy. The digit 1 stands for one thousand, and the digit 6 stands for six. That is, 1776 = 1 1000 + 7 100 + 7 10 + 6 1 or 1776 = 1 103 + 7 102 + 7 101 + 6 100 Technically, we can distinguish the numeral ‘1776’from the number 1776, just like we distinguish the three-letter word ‘cat’from a cat. Another numeral that stands for 1776 is ‘MDCCLXXVI’. We say that the string of digits ‘1776’is the decimal representation of the number 1776, or the base-10 representation. If we want to get hold of the last digit in the decimal representation of the number we can use the Python operation %. The number n%10 is the last digit in the decimal representation of n. Try it with 1776. That’s because 1776 = 177 10+6. If we want to get hold of the next to the last digit of 1776, we look at 177%10. The number 177 is obtained by by writing 1776/10. Here is a short program that illustrates this: n = 1776 print n, n/10, n%10 Run this program. You should see: 1776 177 6. The two commas separate the three numbers on the same line, but they don’t appear on that line with the numbers. Now we want to do the same thing with 177, so we add two lines to the program: n = 1776 print n, n/10, n%10 n = n/10 print n, n/10, n%10 The third line replaces n by n=10, that is, it will replace 1776 by 177. The fourth line is the same as the second line because we want to see the same things, but with 177 rather than with 1776. 5
Run this program. You should see 1776 177 6 177 17 7 We can continue by repeating those two lines several more times: n = 1776 print n, n/10, n = n/10 print n, n/10, n = n/10 print n, n/10, n = n/10 print n, n/10, n = n/10 print n, n/10,
n%10 n%10 n%10 n%10 n%10
Maybe I went overboard there. Run this program. You should see 1776 177 6 177 17 7 17 1 7 1 0 1 0 0 0 Notice that we have picked o¤ the four digits of 1776 as the last numbers on each line. I suppose we can consider the number 0 at the end of the …fth line as the coe¢ cien of 104 in the representation of 1776 as 0 104 + 1 103 + 7 102 + 7 101 + 6 100 but we never write the digit 0 as the …rst digit in a number. So I should have quit as soon as n became 0. We want to repeat the lines print n, n/10, n%10 n = n/10 as long as n remains positive. But we don’t want to write those lines over and over again. Instead we write 6
n = 1776 while n > 0: print n, n/10, n%10 n = n/10 There are several things to notice here. The …rst is the colon after “while n > 0”. That is essential. The second is that the next two lines are both indented. That’s so Python will know to execute both of them until n becomes zero. If you write this program in the IDLE editor (which you should), the colon will cause the next line to be indented automatically. If we had written n = 1776 while n > 0: print n, n/10, n%10 n = n/10 our program would have printed out 1776 177 6 until doomsday. What do you think would happen if we had written n = 1776 while n > 0: print n, n/10, n%10 n = n/10 Try it.
2
Prime numbers
A prime number is an integer that is greater than 1, but is not the product of two integers that are greater than 1. The two smallest prime numbers are 2 and 3. The number 4 is not prime because 4 = 2 2; the number 51 is not prime because 51 = 3 17. The …rst twenty prime numbers are 2; 3; 5; 7; 11; 13; 17; 19; 23; 29; 31; 37; 41; 43; 47; 53; 59; 61; 67; 71
2.1
The smallest prime factor
We want to write a Python program that computes the smallest prime factor p of a given number n. That is, we want to implement Proposition 31 of Book VII of Euclid’s Elements which says that any number greater than 1 is divisible by a prime. 7
You can do this in the interactive mode, but it is less harrowing to do it in the IDLE mode. In that mode, we work with a (built in) text editor on a …le containing a Python program. You can create such a …le from the IDLE interactive mode: open a new window by clicking on the “File” button and then choosing “New Window”. An IDLE editing window comes up. You are now set to write some Python code which you can save afterwards by clicking on the “File” button and then choosing “Save As”. At that point you will have to choose where you want to save your …le, and what its name will be. Call it “…ddle.py”, or something more descriptive, but with the “.py” extension. In the IDLE editing window, type the short version of the classic …rst program: print "Hello" If you are writing a program in the IDLE editing window, you have to use the word print in order to get any output. The quotation marks indicate that the word Hello is text. Without the quotation marks, Python would assume that it was a variable. You can use single quotes or double quotes. The single quote on my keyboard is on the same key as the double quote. I can’t seem to get an appropriate single quote with the word processor I’m using. The best I can do is print ’Hello’ To run the program, press the F5 key. If you haven’t named the program …le before, you will be asked to do so now. Otherwise, Python will simply ask you if it is okay to save the …le, which you will normally agree to. The output should then appear in another window called "Python shell". This window is essentially the interactive window that you worked with before. So you will normally have two windows going: one where you write your program, and one where you see your output. The output for this program should be Hello. Try running the program after removing the quotation marks. You should get an ugly error message in red saying that Hello is not de…ned. Without putting back the quotation marks, insert the line Hello = 3 at the beginning of the …le, before the print command. This will set the variable named Hello equal to 3. Run the program again to see what happens. 8
The smallest prime factor of n is the smallest integer p greater than 1 which divides n. We might as well assume that n 0 because if n < 0, we could look at n instead. If n = 0, then I guess its smallest prime factor is 2; what do you think? If n = 1, then it has no prime factors. (Nobody considers 1 to be a prime, although one can argue that it is.) Those are the only exceptional cases: The number 0 is exceptional because it is smaller than its smallest prime factor; the number 1 is exceptional because it has no prime factor. So, for the computation, you may assume that n > 1. You want to try to divide n successively by 2; 3; 4; 5; : : : until you are successful. You can do that with the function n % m. So you want to see when n % m is …rst equal to zero. The condition that n % m is equal to zero is written n % m == 0 with two equal signs (as in C). A single equal sign is used in an assignment statement: x = a+b says to set the value of x equal to a+b. The expression x == a + b doesn’t say to do anything— it has the value True if x is equal to a + b, and the value False if x is not equal to a + b. An expression that takes on the values True or False is called a boolean expression. Another boolean expression is x < y. A typical use of boolean expressions is in an if statement. The statement if n % m == 0: print ’Hello’ prints out ‘Hello’ if m divides n. The boolean expression is n % m == 0. Note the colon. You need that. It separates the boolean expression from the commands. Here we have only one command: print ’Hello’. Exercise 1. What do you see if you print the boolean expression 3 % 2 == 0? The boolean expression 2 < 3? What if you print ’2 < 3’?
2.2
Using a for-statement
Suppose n > 1 is an integer. We want to run through the integers m, starting at 2, to see if any of them divide the positive integer n. When we come across one that does, we’ll print it out so we can see it. There is at least one that does, namely n itself. We can do this as follows for the integer n = 91: n = 91 9
for m in range(2,n+1): if n % m == 0: break print m Note the colons after the for-statement and after the if-statement. The “break” instruction says “get out of this for-statement”. The indentations are very important in Python. They tell you that the for-statement goes on until the statement print m. The list range(2,n+1) consists of those integers m such that 2 m < n + 1. Note that 2 is an allowable value of m, but n + 1 is not. In general, the set range(a,b) consists of those integers m such that a m < b. The value of m when we exit the for-loop will be the smallest integer greater than 1 that divides n. Exercise 1. Write this program in your …le …ddle.py, or write it in a another …le with a name like temp.py. Run this program using di¤erent values of n. What can you say about n if the program prints out n?
2.3
Testing the algorithm
You should test the program to see if it works. Of course you just could try it on a few selected numbers, and you should do that. Another thing you could do is print out what it does on the …rst 100 numbers greater than 1 (for example) and eyeball the results to see if they look okay. This, of course, would be done with another for-loop, which would start: for n in range(2,102): Inside that for-loop we have to put our original for-loop. Moreover, you should not just print out m, you should print out both n and m, so you will get a list of pairs: the number, and its smallest prime factor. Something like print n,m which prints out n followed by a space followed by m.
2.4
De…ning a function
Better yet, you can de…ne a function that takes a natural number n > 1 and returns its least prime factor. Then you can call that function instead of having to worry about nested for-loops. You already have the required lines of code, you just have to write it down as a function: 10
def spf(n): for m in range(2,n+1): if n % m == 0: return m The …rst line says that we are de…ning a function called spf that will act on a variable n. The command “return m” makes m the result of applying the function spf to n. You don’t have to write break to get out of the loop because a return statement takes you out of the whole function. To test this function, write a for-loop that runs n from 2 to 50, say, and print out n together with the smallest prime dividing n. Your print statement will look something like print n, spf(n)
2.5
Speeding the algorithm up
This is a dumb algorithm. For one thing, it’s pointless to see if m divides n when m2 is greater than n. Why is that? Well, if m2 > n and m divides n, then n=m < m also divides n so we would have already broken out of the loop when we tested the smaller number n=m. Once m2 is greater than n, we already know that n is prime, so we should just return n. Notice that if n is around 1000000, this means that you will be doing around 1000 tests rather than 1000000 tests, so this improvement is well worth doing. It doesn’t take much, just (essentially) one more line: def spf(n): for m in range(2,n+1): if n % m == 0: return m if m*m > n: return n You can write this in fewer lines by putting the return-statements up on the same lines as the if-statements: def spf(n): for m in range(2,n+1): if n % m == 0: return m 11
if m*m > n: return n The upper limit n + 1 is only necessary when n = 2, otherwise we could use the upper limit n (why is that?). We could add a line after the for-loop that returns 0, so that the function will return something even if n is less than 2, but we are really only interested in what happens when n 2.
2.6
Goldbach’s conjecture
Goldbach’s conjecture is that you can write any even number greater than 2 as the sum of two primes. Here is a short table showing how that works: 4=2+2 6=3+3 8=3+5 10 = 3 + 7 12 = 5 + 7 14 = 3 + 11 16 = 3 + 13 18 = 5 + 13 20 = 3 + 17 22 = 3 + 19 24 = 5 + 19 26 = 3 + 23 28 = 5 + 23 30 = 7 + 23 32 = 3 + 29 Some even numbers can be written as sums of two primes in more than one way. For example, 10 = 3 + 7 = 5 + 5 and 22 = 3 + 19 = 5 + 17 = 11 + 11. Goldbach’s conjecture is one of the big unsolved problems in mathematics. Nobody knows whether it is true or false. About twenty years ago, Apostolos Doxiadis wrote a novel called Uncle Petros and Goldbach’s conjecture. The main character of this novel was determined to settle Goldbach’s conjecture. The publishers o¤ered a prize of one million dollars to anyone who proved Goldbach’s conjecture within two years. As I recall, Uncle Petros goes o¤ the deep end when he …nds out that it is conceivable that Goldbach’s conjecture is true, yet not provable. That’s from a famous result in logic by Kurt Gödel, who was a bit crazy himself. Be that as it may, we can write a program that tries to write even numbers as sums of two primes. The number 4 is an anomaly, as it is the only even number that can be written as the sum of two primes where one of the primes is 2. In fact, Goldbach’s conjecture is often stated in the form: any even number greater than 4 is the sum of two odd primes. So we want to run through some even numbers and try to write each one as the sum of two odd primes. An even number is a multiple of 2, so we want to run through numbers of the form 2n for n = 2; 3; 4; 5; 6; : : :. Let’s start out by running n from 2 to 16, so that we will duplicate the results in the table above. We can do that with the line for n in range(2,17): 12
If 2n is the sum of two primes, then the smaller prime is at most n, so we want to run through the primes p with p n. We also want 2n p to be a prime. So we run through the numbers p with p n, and test to see if p and 2n p are both primes. That’s why we write the second line as follows: for n in range(2,17): for p in range(2,n+1): To test whether p and 2n p are both primes, we use an if-statement and our function spf. Here is what a third line might look like: for n in range(2,17): for p in range(2,n+1): if spf(p) == p and spf(2*n-p) == 2*n-p: print 2*n,"=",p,"+",2*n-p Notice the use of our function spf to check whether p and 2n p are primes. Not also the use of the word “and” to make the if-statement dependent on two conditions. Finally, notice that we have to write 2*n, not 2n to indicate the number 2n. Run this program. If everything is working right, it should print out all possible ways of writing each even number as the sum of two primes. Try using di¤erent numbers for 17. Exercise 1. Write a program that, instead of printing out the di¤erent ways each even number can be written as the sum of two primes, prints the number of ways each even number can be written as the sum of two primes. So next to the number 90 it would print the number 9, because 90 can be written in 9 ways as the sum of two primes. At least according to my calculations. Exercise 2. What is the smallest even number that can be written as a sum of two primes in 11 ways? What is the smallest even number that can be written as the sum of two primes in exactly 11 ways? It’s a little cryptic to use the function spf to see if a number is prime. Here is an function that does this directly. def prime(n): if n < 2: return False for m in range(2,n): if n % m == 0: return False return True
13
The purpose of the …rst line is to avoid returning True for negative numbers and for the numbers 0 and 1. The next two lines test to see if n is divisible by a number m such that 2 m < n, and returns False if it is. Note that if n = 2, then there are no such numbers m. If n does not get eliminated this way, then the last line returns True. A re…nement on this function is to add a line that returns True as soon as m2 > n, because in that case we already know, without further testing, that n must be prime. So we could write def prime(n): if n < 2: return False for m in range(2,n): if n % m == 0: return False if m*m > n: return True return True This re…nement helps if we are testing a very large prime.
2.7
Sophie Germain primes
Sophie Germain, a French mathematician who lived from 1776 to 1831, worked on one of the most famous problems in mathematics: Fermat’s last theorem. One of her results concerning this problem involved primes p such that 2p + 1 is also a prime. These primes have come to be known as Sophie Germain primes. The …rst few Sophie Germain primes are 2, 3, 5, 11, and 23. You can see that 2 2 + 1 = 5 is a prime, as are 2 3 + 1 = 7, 2 5 + 1 = 11, 2 11 + 1 = 23, and 2 23 + 1 = 47. The primes 7 and 13 are not Sophie Germain primes because 2 7 + 1 = 15 and 2 13 + 1 = 27 are not primes. Fermat’s last theorem says that if p is an odd prime, then there are no solutions to the equation xp + y p = z p with x, y, and z positive integers. The so-called “…rst case”of Fermat’s last theorem is to show that there are no solutions with x, y, and z, not divisible by p. Sophie Germain proved that the …rst case of Fermat’s last theorem is true if p is a Sophie Germain prime. Fermat’s last theorem was not the last theorem that Fermat proved, or the last theorem that Fermat claimed to be true. For a long time it was the only theorem of Fermat that remained unproved, among the theorems that he had claimed were true. In 1995, Andrew Wiles published a proof of Fermat’s last theorem, 358 years after it was stated. 14
If p is a Sophie Germain prime, then the prime q = 2p + 1 is said to be a safe prime. This term has its origin in cryptography. It refers to the fact that q 1 does not have many prime factors— in fact it has only two: 2 and p. That makes the prime q useful for certain encryption algorithms. A prime q is safe exactly when the number (q 1) =2 is prime. The largest known Sophie Germain prime is 18543637900515 2666667
1
A Cunningham chain (of the …rst kind) is a sequence of primes such that each one is twice the preceding one plus 1. So the sequence 2, 5, 11, 23, 47 is a Cunningham chain. This chain cannot be extended because 2 47 + 1 = 95 is not a prime. Another Cunningham chain is the sequence 89, 179, 359, 719, 1439, 2879. The longest known Cunningham chain consists of 17 primes, the …rst of which is 2759832934171386593519. A Cunningham chain is complete if it cannot be extended, in either direction, to form a larger Cunningham chain. So the …rst term in a complete Cunningham chain is not a safe prime, and the last term is not a Sophie Germain prime. Note that in the Cunningham chain 89, 179, 359, 719, 1439, 2879, the number 89 is not safe because (89 1) =2 = 44 is not a prime, and 2879 is not a Sophie Germain prime because 2 2879 + 1 = 5759 = 13 443 is not a prime. Here is a simple function that returns True when applied to numbers that are prime but not safe (unsafe primes), and False otherwise. def unsafe(n): if prime(n) and not prime((n-1)/2): return True return False Exercise 1. Write a program to …nd the longest Cunningham chain whose …rst prime is less than 1000. This chain will necessarily be complete. Exercise 2. One can think of the primes as being partitioned into complete Cunningham chains. The chains of length one are the primes that are neither Sophie Germain primes nor safe primes. The …rst such chain is 13. What is the …rst chain of length two? Exercise 3. Write a program that lists all the Sophie Germain primes p less than 1000 that are not safe primes, together with the length of the complete Cunningham chain starting at p.
15
2.8
There are in…nitely many primes
In Book VII, Proposition 37, Euclid proves that any number greater than 1 is divisible by a prime number. The function spf(n) is an implementation of that proposition: you give it a number n > 1, and it returns a prime number that divides n. Of course what spf(n) actually does is to return the smallest number p > 1 that divides n. This number p is necessarily prime because if p had a nontrivial factor, that factor would be smaller than p and would also divide n. There is a great presentation of Euclid’s elements by David Joyce on the web, complete with Java applets to illustrate the propositions. The url is aleph0.clarku.edu/~djoyce/java/elements/elements.html Click on the number of the book that you want, then click on the proposition that you are interested in. In Book IX, Proposition 20, Euclid proves that prime numbers are more than any assigned multitude of prime numbers. By that he meant that if you are given any (…nite) list of prime numbers, then you can construct a prime number that is not on that list. This is a positive formulation of the statement that there are in…nitely many primes. We can implement this proposition of Euclid also. Euclid’s proof says to multiply all the primes in the given list together to get a product P , and then consider the number P + 1. The number P + 1 cannot be divisible by any of the primes on the list, because P is divisible by all those primes. But Proposition 37 of Book VII says that P + 1 is divisible by some prime. So that prime cannot be on the list. This procedure can be used to generate a sequence of primes, starting from nothing. To get a prime, we have to start with a list of primes, but we can take the initial list to be empty! What is the product P of the primes on an empty list? As we shall see, when we actually write down the program, the product of an empty list of numbers is equal to 1. That might seem a little surprising, but it turns out to be very natural. So P + 1 is equal to 2, the …rst prime generated by Euclid’s construction. So our list starts out empty, which in Python is the list [ ]. Then we get the list [2]. Applying Euclid’s construction to that list gives P = 2 and P +1 = 3. So the next prime we get is 3, and our list of primes becomes [2,3]. Continuing in this way, you can see that we get the prime 7 = 2 3 + 1, then the prime 43 = 2 3 7+1. The next number we consider is 2 3 7 43+1 = 1807. 16
But 1807 = 13 139 is not prime. So, since we are taking the smallest prime dividing P + 1, the next prime on our list is 13. Here is a program that multiplies all the numbers on a list L together: P=1 for i in L: P = P*i After this program has executed, the variable P will be the product of the numbers in the list L. For example, if L = [2,3,5], then P will start out as 1, then become P i = 1 2 = 2, then P i = 2 3 = 6, then 6 5 = 30. You can see that if the list L is empty, then P remains equal to 1, its initial value, because there are no numbers i in L. So how do we implement Book IX, Proposition 20? First we decide how many times we want to repeat the basic construction. Let’s call that number m, and set it equal to 5 at …rst. So our …rst line will be m = 5. Then we set up the list L which is initially empty. So our second line will be L = [ ]. Then have some variable run through the numbers from 0 to m 1. It makes no di¤erence what we call that variable, the idea is simply to repeat the basic construction m times. Then we multiply all the numbers in the list L, as before. So our …rst few lines will be m=5 L = [] for n in range(m): P=1 for i in L: P = P*i Now what? The construction says to …nd a prime that divides P + 1. So our next line should be to compute spf(P+1). Call that prime p and print it out so we can see what’s happening. Then, and this is crucial, we have to tack p onto the end of the list L. Perhaps the easiest way to do that is with the command L.append(p). Another way is L = L + [p], or even L += [p]. We can use a plus sign to put two lists together. I …nd that easier to remember, but you have to be sure you are putting two lists together, so we need to write [p] rather than p. So our program becomes m=5 L = [] for n in range(m): P=1 for i in L: P = P*i 17
p = spf(P+1) print p L.append(p) Notice that this program calls on the function spf, so the de…nition of that function has to be in our …le also. When I try to run this program for m = 9, Python, or my computer, gets angry because it can’t hold a list of the size required in the function spf. Because of that, I modi…ed the program for spf so that it doesn’t use the range operation, which is what creates the big list. I rewrote it this way: def spf(n): i=2 while i*i < n+1: if n%i == 0: return i i = i+1 return n Do you see what that does? I got rid of the for-statement and replaced it by a while-statement. The indented commands below the while-statement keep repeating as long as the condition i2 < n + 1 holds. So we have to change i by hand, so to speak, whereas before the for-statement changed it automatically. If we get to the point where the condition i2 < n + 1 fails to hold, then we know that n is prime because we have tried to divide n by on all numbers whose squares are at most n. With this new de…nition, I managed to get the program to run with m = 14. The fourteenth prime that it generated was 5471. With a little more patience on my part, it ran with m = 15. The …fteenth prime generated was 52662739. What is the eighth prime in this sequence? If your program is taking a long time to factor some large number, there is help on the web. A good site is www.alpertron.com.ar/ECM.HTM which will factor very large numbers in very little time. There are at least two other ways to implement Book IX, Proposition 20. The …rst is to multiply the …rst few primes together, add one, and …nd a prime factor of the result. So we would start with 2. As 2 + 1 = 3 is prime, the next prime we get is 3. As 2 3 + 1 = 7 is prime, the next prime we get is 7. As 2 3 5 + 1 = 31 is prime, the next prime we get is 31. See how this algorithm di¤ers from our …rst in which we looked at 2 3 7+1 = 43, omitting the prime 5. The next prime we get in this new sequence is 2 3 5 7+1 = 211, 18
which is also prime. If 211 were not a prime, we would calculate its smallest prime factor. Exercise 1. Write a program that computes this sequence. Do you always get primes without factoring, or do we sometimes get a composite number which we have to factor to get our new prime? Another way to show there are in…nitely many primes is to show that for each number n, prime or not, there is a prime greater than n. In a way, this is the simplest algorithm: we simply …nd a prime factor of n! + 1. That number cannot be divisible by a prime i n, because if i n, then i divides n!. The …rst few numbers we get that way are 1! + 1 = 2, 2! + 1 = 3, and 3! + 1 = 7. The next number is 4! + 1 = 25, which is not a prime but all of its prime factors are bigger than 4. The next number is 5! + 1 = 121 which (I think) is a prime. Exercise 2. Write a program that uses this procedure to …nd a prime greater than n for as many numbers n as you can. Print out n, followed by the prime that is greater than n, for each number n.
2.9
Largest prime factor
Suppose we want to calculate the largest prime factor of a number n. Here is a plan. First compute the smallest prime factor p of n. We already have a program for that. If p = n, then p is the largest prime factor of n. Otherwise, the largest prime factor of n is equal to the largest prime factor of n=p. That’s because p is the smallest prime factor of n, and n = p n=p. How to we turn this plan into a program? The …rst couple of lines are clear: def Lpf(n): p = spf(n) if p == n: return n Now what? What we want to do now is …nd the largest prime factor of n=p. That is the function that we are in the middle of de…ning! In fact, we can use that function as part of its own de…nition. This is known as a recursive de…nition. So we simply add one more line: def Lpf(n): p = spf(n) if p == n: return n 19
return Lpf(n/p) This works because n=p is always smaller than n. What actually happens when we compute Lpf(50)? The …rst line of the de…nition calculates the smallest prime factor p = 2 of 50. As 2 is not equal to 50, we go to the third line which has us compute Lpf(25). Now we are at the …rst line of the program with n = 25, which calculates the smallest prime factor p = 5 of 25. As 5 is not equal to 25, we go to the third line which computes Lpf(5). To do that, we …nd the smallest prime factor p = 5 of 5. But then n = p, so, in accordance with the second line of the de…nition, we return 5, the largest prime factor of 50.
2.10
Complete factorization
How do we get a program to tell us what all the prime factors of a number are? We want to enter a number n and have the output be a list of the primes dividing n. Probably we want to allow repetitions on this list, so when we enter the number 72, the list that gets returned is [2; 2; 2; 3; 3] rather than just [2; 3]. Note that a list is Python is written as a sequence of elements, separated by commas, and enclosed in square brackets. If we “add”two lists in Python, we get the concatenation of the two lists. Thus [1] + [2] = [1; 2] [1; 2; 10] + [2; 13] = [1; 2; 10; 2; 13] [1] + [] = [1] The natural way to handle this problem is via a recursive function, one that calls on itself. Let’s denote the function we want to de…ne by allpf (n). Then what we want to do is …rst compute m = spf (n) and then form a list allpf (n) whose …rst element is m and whose remaining elements form the list allpf (n=m). The list allpf (n) can be constructed in Python as the sum of two lists: allpf (n) = [m] + allpf (n=m)
20
This last equation is the recursion: we de…ne allpf in terms of itself. How does it work in practice? If n = 12, then m = spf (12) = 2, and n=m = 6, so we have allpf (12) = [2] + allpf (6) Proceeding, we get allpf (6) = [2] + allpf (3) so allpf (12) = [2] + [2] + allpf (3) Finally, allpf (3) = [3] + allpf (1) = [3] + [] = [3] so allpf (12) = [2] + [2] + [3] = [2] + [2; 3] = [2; 2; 3] This works because of two things. One is that the number n=m that we apply the function allpf to on the right, is always smaller than the number n that we apply allpf to on the left. The other is that if n is small enough (equal to 1), then we know directly what allpf (n) is. So here is the general idea. If n = 1, then return the empty list. If n > 1, then set m = spf (n), and return the list [m] + allpf (n=m). Here is a formal de…nition in Python: def allpf(n): if n == 1: return [] m = spf(n) return [m] + allpf(n/m)
2.11
More on recursive functions
The prototype recursive function is one that computes the factorial function, the product of the integers from 1 to n: n! = n (n
1) (n
2)
3 2 1
The key fact is that n! is equal to n times (n 1)!, at least if n is positive, as you can see by looking at the product. Thus if we could compute (n 1)! we
21
would know how to compute n!. The computation for 4! would go as follows: 4! 3! 2! 1!
= = = =
4 3 2 1
3! 2! 1! 0!
but now we can’t go further, we have to know what 0! is. Well, 0! is equal to 1. That’s our exit condition. Then we work our way backwards through the equations to …nd that 1! 2! 3! 4!
= = = =
1 2 3 4
0! = 1 1! = 2 2! = 3 3! = 4
1=1 1=2 2=6 6 = 24
The program would look like: def fac(n): if n == 0: return 1 return n*fac(n-1) What happens when it runs on n = 4? When we run fac(4), it tries to return 4*fac(3), so it has to run fac(3). We now have two programs running at once: fac(4) and fac(3), with fac(4) waiting for the result from fac(3). Similarly fac(3) tries to return 3*fac(2), so it has to run fac(2). We now have three programs running at once. And so on. We can indicate this by a table: program fac(4) fac(3) fac(2) fac(1) fac(0)
returns 4*fac(3) 3*fac(2) 2*fac(1) 1*fac(0) 1
At the end we have …ve fac programs running at once. But fac(0) knows what to do without calling fac any more: it returns 1. Now fac(0) = 1 is passed to the fac(1) program giving the result fac(1) = 1*1 = 1. Then fac(1) = 1 is passed to the fac(2) program giving the result fac(2) = 2*1 = 2. This result is passed to the fac(3) program, yielding fac(3) = 3*2 = 6, and …nally this result is passed to the fac(4) program yielding fac(4) = 4*6 = 24. 22
2.12
Working with lists
A list is a sequence indexed by the integers 0; 1; 2; : : : ; n 1. The n elements of the list a are denoted a[0], a[1], a[2], . . . , a[n-1]. The number n is the length of the list and can be accessed by writing len(a). A string s can be thought of as a special type of list whose elements are alphanumeric characters. Its length is also denoted len(s), but a string is handled a little bit di¤erently from a list. The simplest way to create a list is by the statement a = [] which creates a list with no elements— an empty list. An empty list has length 0. So, if after de…ning the list a above, you printed out len(a), you should see 0. You can put an element m onto the end of an array a by writing a.append(m). If a is an empty list, then a.append(17) changes a into the list [17]. If you want a list containing the squares of the numbers from 0 to 9, you can get one by …rst setting a = [] and then running the loop for i in range(0,10): a.append(i*i) We can stick an element m onto the beginning of the list a by writing a.insert(0,m). If take the list a generated by the loop above, and then write a.insert(0,22), the list a would become [22,0,1,4,9,16,25,36,49,64,81]. Actually, I have trouble remembering how to use append and insert. I …nd it easier to use addition of lists. So instead of writing a.append(m), I write a = a + [m], and instead of writing a.insert(0,m), I write a = [m] + a. The general idea is that when you add two lists, the result is a list consisting of the two lists put together. The list [22,0,1,4,9] + [16,25,36,49,64,81] is the list [22,0,1,4,9,16,25,36,49,64,81]
3
The Euclidean algorithm
The Euclidean algorithm is one of the oldest and best algorithms we have. It computes the greatest common divisor of two positive integers a and b. 23
You can …nd it in Book VII Proposition 2 of Euclid’s Elements. Euclid also showed that any number that divides both a and b divides their greatest common divisor. I think of that fact as being the “algebraic gcd property”. Here is a short program that computes the gcd: def gcd(a,b): while a!=0: a,b = b%a,a return abs(b) The Euclidean algorithm is most naturally written recursively. Euclid pointed out that the common divisors of a and b (those numbers that divide both a and b) are the same as the common divisors of a and b a. So if 0 < a b, we can reduce the problem of …nding gcd (a; b) to that of …nding gcd(a; b a). The latter is a simpler problem because the numbers are smaller (certainly their sum is smaller). We can re…ne that observation a bit for our purposes by noticing that we can repeatedly subtract a from b until we get a number that is smaller than a. Actually, Euclid noted that also: he talked about repeatedly subtracting the smaller number from the larger number. If you repeatedly subtract a from b until b becomes smaller than a, you end up with the remainder you get when you divide b by a. (Recall that division of positive integers can be thought of as repeated subtraction.) So using the Python % notation for the remainder, the key equation is gcd (a; b) = gcd (b % a; a) Here the b % a is written …rst because it is (strictly) smaller than a. Of course b % a might be equal to zero, in which case we are done because gcd (0; a) = a. This gives us our exit condition from the recursion: if a is 0, then gcd (a; b) = b. The usual convention is that gcd (0; 0) = 0 even though, strictly speaking, there is no greatest common divisor of 0 and 0. However, zero is obviously the algebraic gcd of 0 and 0 because any number that divides both 0 and 0 divides zero (and zero is the only number with that property). Rather than making your algorithm foolproof, at least at …rst, just make it work when it is handed integers a and b with 0 a b. Use the exit condition gcd(0; b) = b and the recursion displayed above. Test your algorithm on a few small pairs a and b where you know what the answer is.
24
There is a built-in Python function that will return gcd (a; b). You can import it from the module fractions. If you put the line from fractions import gcd at the top, then you can use their function gcd(a,b) in your programs.
3.1
The Euler '-function
Two positive integers a and b are said to be relatively prime, or coprime, if they have no common divisors except for 1. Notice that 1 is relatively prime to any positive integer. It’s easy to see that two numbers a and b are relatively prime exactly when gcd (a; b) = 1, so the Euclidean algorithm provides a test for when a and b are relatively prime. The Euler '-function is de…ned, for n > 1, by setting ' (n) equal to the number of positive integers less than n that are relatively prime to n. Thus ' (10) = 4 because the numbers less than 10 that are relatively prime to 10 are 1, 3, 7, and 9. Usually people set ' (0) = 0 and ' (1) = 1, but we really don’t care about those values, especially ' (0). We can justify ' (1) = 1 by modifying the de…nition of ' (n) to read “the number of positive integers less than or equal to n that are relatively prime to n.”This, in fact, is the usual de…nition. It also gives ' (0) = 0. Once you get your gcd function working, you can use it to compute the ' function. For each m just run through the numbers 1; 2; : : : ; m, checking each one to see if it is relatively prime to m, and counting how many times that happens. After writing such a function, test it by printing out, in two columns, the values m and ' (m) for m = 2; : : : ; n. The …rst few values of the Euler '-function are n 0 1 2 3 4 5 6 7 8 9 10 ' (n) 0 1 1 2 2 4 2 6 4 6 4 Verify this table. As a …nal check on your ' function, you can compute it in a di¤erent way. The formula is Q 1 ' (n) = n 1 p p2P
where P is the set of primes that divide n. So ' (10) = 10 1
25
1 2
1
1 5
and
1 1 1 2 3 If you write it that way, you will be dealing with real numbers, at least as intermediate values. In order to deal only with integers, you can rewrite the formula as ' (12) = 12 1
n
Q
p2P
1
1 p
=n
Q
p
1 p
p2P
=Q
10 4=4 10
For Q n = 12, the set P is f2; 3g and the product 1) is 1 2 = 2 so p2P (p ' (12) =
p p2P
p2P
So Q for n = 10, the set P is f2; 5g and the product 1) is 1 4 = 4 so p2P (p ' (10) =
Q
n Q
p2P
Q
p2P
(p
1)
p is 10. The product
p is 6. The product
12 2=4 6
You can use allpf(n) to …nd the set P . What you need to do is to eliminate the duplicates from the list that allpf(n) returns. It’s probably better to modify the function allpf(n) so that it doesn’t return any duplicates. When you …nd the smallest prime dividing n, keep dividing n by that prime until you can’t anymore, then go on to …nd the smallest prime dividing what’s left. You should probably give the modi…ed function a di¤erent name. Let’s do it. We’ll call the function allpd(n) for “all prime divisors”. def allpd(n): if n == 1: return [] #the number 1 has no prime divisors i=2 #the number 2 is the smallest prime while i*i = len(G): G.append(0) G[g]+=1 lastprime = i return G A prime triple (or triplet) is a sequence of three primes p0 < p1 < p2 such that p2 = p0 + 6. Here are the …rst six examples: (5; 7; 11); (7; 11; 13); (11; 13; 17); (13; 17; 19); (17; 19; 23); (37; 41; 43) You can see a list of the …rst elements of the prime triples of the form (p; p + 2; p + 6), like (5; 7; 11), from 5 to 5477 at oeis.org/A022004, and one of the …rst elements of the prime triples of the form (p; p + 4; p + 6), like (7; 11; 13), from 7 to 5437, at oeis.org/A022005. Exercise 1. Write a program that counts the number of prime triples of the form (p; p + 2; p + 6) in the …rst two thousand numbers. Compare your results with those of Thomas R. Nicely on his site at http://www.trnicely.net/ triplets/t3a_0000.htm.
5
Mersenne primes
A Mersenne prime is a prime of the form 2n 1. So 3 = 22 1 is a Mersenne prime, as are 7 = 23 1 and 31 = 25 1. Of course 15 = 24 1 is not a prime at all, let alone a Mersenne prime. In fact it is not di¢ cult to show that if 2n 1 is a prime, then so is n. Essentially the argument is 2ab
1 = (2a
1) 2a(b
1)
+ 2a(b
34
2)
+
+ 2a + 1
if you can call that an argument. It shows that 2a 1 is a nontrivial factor of 2ab 1 if a is a nontrivial factor of ab. So the question is, for what primes p is 2p 1 a prime. We denote 2p 1 by Mp , in honor of Mersenne. We have seen that M2 , M3 , and M5 are primes. What about M7 = 27 1 = 127. Yes, it’s also prime. Marin Mersenne said, in 1644, that for the primes p 157, the ones for which Mp is prime are 2; 3; 5; 7; 13; 17; 19; 31; 67; 127; 157. In 1750, Euler showed that M31 was a prime. In 1883, Pervouchine showed that M61 is prime, so Mersenne missed one. Mersenne primes are interesting because, among other things, they are tied up with perfect numbers. Euclid talked about perfect numbers, and showed that an even number is perfect exactly when it is of the form (2n 1) 2n 1 , and 2n 1 is prime. So we get a perfect number for n = 2; 3; 5; 7; 13; : : :. These numbers are 6, 28, 496, 8128, 33 550 336, . . . . The …rst four of these numbers have been known since antiquity. St. Augustine made a big deal out of the fact that 6 was a perfect number, saying that God created the world in six days because of this. No one knows whether or not there are any odd perfect numbers. Write a program that …gures out for which primes p < 60 the number Mp is a prime. When Mp is not prime, this program should print out its smallest prime factor. However, that there is technical problem with the function spf when applied to very large numbers. Here is the function spf as we de…ned it before: def spf(n): for m in range(2,n+1): if n % m == 0: return m if m*m > n: return n The problem is that the list, range(2,n+1), is just too big. What we need to do is to de…ne the function spf without forming that list. For this purpose we use a while-loop instead of a for-loop. The …rst three lines would be def spf(n): m=2 while m*m 2, then there are no nonzero integer solutions x; y; z to the equation xn + y n = z n . Fermat’s last theorem 37
is very di¢ cult to prove, and remained unproved for over three hundred years after Fermat stated it. Fermat’s little theorem is fairly easy to prove and you can use Google to …nd lots of proofs of it on the web. Our …rst project with Fermat’s theorem will be to check it on lots of examples. So we want to take some primes n, and some numbers a with 1 a < n, and see if an 1 1 (mod n). Of course this equation holds for a = 1, so we need only look at numbers a such that 1 < a < n. Just checking the equation on primes n is a little boring. It is also a little dangerous because the output of the program will just be, “yes, it checks”, so we won’t have any evidence as to whether the program is working right or not. More interesting would to check the equation not only on primes n but also on composites. In fact, we will be more interested in what happens with composites than with primes because we are going to use Fermat’s theorem to test whether or not n is a prime. The test will be: choose a number a from f2; 3; : : : ; n 1g and compute an 1 modulo n. If the result is 1, then n might be a prime, or it might not. But if the result is not 1, then n is de…nitely not a prime. So our …rst project will be to run through the integers n from 2 to 100, and for each n run through the integers a from 2 to n 1 to see whether or not an 1 1 (mod n). What do we want the output to be? For each n, we will count the number of integers a from 2 to n 1 such that an 1 is not equal to 1 modulo n. So if n is prime, this count should be zero according to Fermat’s theorem. We want to print out the number n together with the count. A check on the program will be to see if the numbers n where we get a count of zero are exactly the primes. The …rst few lines of output should be: 2. 3. 4. 5. 6. 7. 8. 9.
0 0 2 0 4 0 6 6
We can get a probabilistic test for the primality of a number n by choosing, at random, a number a from 1 to n 1 and seeing if an 1 1 (mod n). To choose a random number from 1 to n 1 in Python, put the line 38
from random import randint at the top of the …le. Then we can use the Python function randint(c,d) which returns a random integer a such that c a d. To set a equal to a random integer between 1 and n 1 we write a = randint(1,n-1) Try running this test 100 times on the number 15906120889 and counting the number of times you get 1. Then try factoring this number with spf.
6.1
Carmichael numbers
A Carmichael number is a number n so that an 1 1 (mod n) whenever gcd(a; n) = 1. So a Carmichael number will pass the Fermat test unless you happen to choose a number a that has a common factor with n. If that were easy to do, then you could just choose such a number a, compute gcd (a; n), which is a quick computation, and you would have a factor of n. Carmichael numbers are sometimes called pseudoprimes. The …rst few Carmichael numbers are 561, 1105, 1729, 2465, 2821, 6601, 8911, 10585, 15841, 29341. Two bigger ones are 294409 = 37 73 109 and 56052361 = 211 421 631. Also interesting are 6733693 = 109 163 379 and 17236801 = 151 211 541. The probability that a number less than 56052361 is relatively prime to 56052361 is 210 420 630=56052361 = 0:99132. So this is the probability that 56052361 passes the Fermat test. The probability that it will pass ten Fermat tests is 0:9913210 = 0:91651, pretty good odds. For all Carmichael numbers less than 1012 , see http://www.kobepharmau.ac.jp/~math/notes/note02.html See also http://math.fau.edu/richman/carm.htm Some other big Carmichael numbers are 492559141 = 367 733 1831, 413138881 = 617 661 1013, 16157879263 = 1667 2143 4523, 25749237001 = 1901 2851 4751, 58094662081 = 2633 4513 4889. What do all these numbers have in common? They are all products of three primes, n = pqr, and n 1 is divisible by p 1, q 1, and r 1. For example, 29341 = 13 37 61 and 29340 = 22 32 5 163 which is divisible by 12, 36, and 60. This re‡ects Korselt’s criterion which says that a number n > 1 is a Carmichael number exactly when n is square free (is not divisible by the square of a prime) and if p is any prime divisor of n, then p 1 divides n 1.
39
6.2
The Miller-Rabin test
The most commonly used probabilistic primality test is the Miller-Rabin test. This test, which is a variant of Fermat’s test, cannot be fooled by Carmichael numbers. If the numbers a that we use to test are chosen at random, then the probability that a composite n will pass the test is less than 1=2. So if we test 20 times in succession, choosing the numbers a independently, then the probability of a composite passing these 20 tests is less than 1=220 , that is, less than 1 in a million. There is one new idea in the test: If the square of a number is 1 modulo n, and n is a prime, then the number has to be either 1 or 1 modulo n. That’s because z 2 1 = (z 1) (z + 1), so if z 2 1 is divisible by a prime n, then n has to divide either z 1 or z + 1. How do we run across a number whose square is equal to 1 modulo n? When the number n passes Fermat’s test. In that case, an 1 is equal to 1 modulo n, and an 1 is the square of a(n 1)=2 . We know that n 1 is even, because n were even, we would know that it wasn’t a prime. So we can check to see if a(n 1)=2 is equal to 1 or 1 modulo n. That already is a better test than just Fermat’s test. Here is the Miller-Rabin test. You are given a number n that wish to test for primality. Write n 1 = 2s d where d is odd. This is always possible: you just keep dividing n 1 by 2 until you get an odd number. For the test, you choose a number a at random so that 0 < a < n. Then you compute x = ad (mod n). The test is to consider, modulo n, the sequence s
x; x2 ; x4 ; x8 ; : : : ; x2
There are s + 1 terms in this sequence (because the exponents of x are s s 20 ; 21 ; 22 ; 23 ; : : : ; 2s ), and the last is x2 = ad2 = an 1 . Of course the last term should be 1— that’s Fermat’s test. Now each term in our sequence is the square of the previous term. So if a term is 1, and the last term must be 1 or we would know that n was not a prime by Fermat’s test, then the previous term must be 1. If that doesn’t happen, we know that n is not a prime. So the good sequences look like 1; 1; 1; 1; 1; 1; 1; 1 1; 1; 1; 1; 1; 1; 1 ; ; ; 1; 1; 1; 1 40
where
is a number di¤erent from
1. The bad sequences look like
; ; ; 1; 1; 1; 1 ; ; ; ; ; ; 1 ; ; ; ; ; ; The bad sequences either don’t end in 1, so the Fermat test fails, or they contain a 1 immediately following a . If we denote the sequence by t0 ; t1 ; t2 ; : : : ; ts , then for the sequence to be good we must have ts = 1 and there must not be an index i such that ti 6= 1 and ti+1 = 1. You don’t need a list to perform this test, but you may …nd it convenient. Just compute x, keep squaring it, looking for the forbidden s z 6= 1 and z 2 = 1, and make sure that x2 = 1. While developing this program you might want to print out the sequence t0 ; t1 ; t2 ; : : : ; ts . Try this test out on the largest Carmichael numbers above. If you …nd that a number passes the Fermat test, but fails the MillerRabin test, then you will have computed a number z so that z 6= 1 (mod n) but z 2 = 1 (mod n). So n divides (z 1) (z + 1), but n does not divide either z 1 or z + 1. In that case, gcd (z 1; n) has to be a proper factor of n, showing directly that n is not prime. This gives a quick way of factoring because the Euclidean algorithm is very fast. For example, for the number 56052361, and the random number 40202214, the sequence is 55252883; 1; 1; 1, so gcd (55252882; 56052361) = 88831 is a factor of 56052361.
7
The sum of the squares of the digits of a number
Consider the function f that takes a number to the sum of the squares of its digits. So f (340779) = 32 + 42 + 02 + 72 + 72 + 92 = 9 + 16 + 0 + 49 + 49 + 81 = 204 After we …gure out how to compute this function, we will want to iterate it and see what happens. That is, after computing f (340779) = 204, we will compute f (204) = 20, then f (20) = 4, then f (4) = 16 and so on. The sequence we get starting with 340779 is 340779, 204, 20, 4, 16, 37, 58, 89, 145, 42, 20 41
and now, of course, the sequence starts repeating. We have found a periodic point, 20, of the function f . That is, f 8 (20) = 20 where f 8 indicates the function f applied 8 times, that is f 8 (m) = f (f (f (f (f (f (f (f (m)))))))) We call f 8 the 8-th iterate of f , and we say that 20 has period 8. We want to investigate the sequence m, f (m), f 2 (m), f 3 (m), . . . for various values of m. We just did it for m = 340779. Notice that not only is 20 a periodic point of f , but so are 4, 16, 37, 58, 89, 145, and 42. They each have period 8. We say that the set f20; 4; 16; 37; 59; 89; 145; 42g is an orbit of the function f . The set f1g is another orbit. It turns out that these are the only orbits of the function f .
7.1
Happy numbers
A happy number is a number m so that f k (m) = 1 for some k. Note that f (1) = 1, so the sequence of iterates is 1 from k on. The number 1 is called a …xed point of f ; it is a periodic point of period 1 Of course 1 is a happy number. The next happy number is 7, which gives the sequence 7; 49; 97; 130; 10; 1. The number 2 is not a happy number because f (2) = 4 which is a periodic point of period 8, so the number 1 will not appear in the sequence. If we want to use a program to study these sequences, we will have to write a function that computes f (m). How do we get hold of the digits of m so that we can square them and add up the results? Consider m = 340779. The easiest digit of m to get hold of is the last one, 9, because 9 = m%10. To get at the next-to-the-last digit, we arrange for it to be the last digit of another number. To do this, we subtract 9, the last digit, from m to get 340770. Now, dividing by 10, we get 34077, and the next digit we want is the last digit of this number. We continue this computation as in the following
42
table m m%10 m 340779 34077 3407 340 34 3
9 7 7 0 4 3
m%10 340770 34070 3400 340 30 0
m
m%10 10 34077 3407 340 34 3 0
Notice that we generate the digits in reverse order, the last one …rst. This makes no di¤erence for the computation of f because we are just going to square the digits and add up the results, and it doesn’t matter in which order we add. There is a recursion for f , which you can pretty much see from our computations, namely f (m) = (m%10)2 + f
m
m%10 10
This tells us what to do with any nonzero m, reducing the computation of f (m) to computing f of a number smaller than m. What about f (0)? You should now be able to write a recursive Python function that computes f . There is a Python trick that computes the sum of the squares of the digits of a number written in base 10. It is sum(int(i)**2 for i in str(n)). The number n is converted to a string of characters str(n). So 123 would be converted to the string "123". Then int(i) converts each character in i in str(n) into an integer, so we get the integers 1 2 3. Each one of those is squared by **2, resulting in 1 4 9, and then sum adds them up. This only works in base 10. Try it. But, of course, what we want to see are not the sequences f (m), where m goes from 1 to n, but the sequences f k (m) where m is …xed and k goes from 1 to n. Exercise 1. Write a recursive Python function that computes f and test it out on the numbers from 0 to 100. Is it correct? Exercise 2. Write a function g (m; n) that prints out the values m; f (m) ; f 2 (m) ; : : : ; f n (m) on a single line. 43
7.2
Numbers whose digits increase
The function f that sums the squares of the digits of a number n, doesn’t care in what order the digits of n appear. For example, f (512) = f (215) = 30. So we can always write f (n) as f (m) where m is a number whose digits appear in increasing order. To construct m, we simply rearrange the digits of n. So we can write f (9717) as f (1779). Notice that we don’t demand that the digits appear in strictly increasing order— we allow consecutive digits to be equal. Notice also that if the digits of a number appear in increasing order, then the digit 0 does not appear. How many numbers less than a million have their digits in increasing order? For 100, we can count them by hand: 0 11 22 33 44 55 66 77 88 99
1 12 23 34 45 56 67 78 89
2 13 24 35 46 57 68 79
3 14 25 36 47 58 69
4 15 26 37 48 59
5 6 7 8 9 16 17 18 19 27 28 29 38 39 49
We can see that the numbers …ll up a little more than half of a ten-by-ten square, which contains 100 little squares. It’s a little more, because if we cut the square exactly in half, from the upper right to the lower left, the ten little squares on the diagonal would be cut in half, so 100=2 = 50 would undercount by 10=2 = 5. So, of the numbers with at most two digits, there are 55 of them whose digits appear in increasing order. What about the numbers with at most six digits, that is, the numbers less than a million? In fact, we can develop a simple formula for how many of those have their digits appearing in increasing order, namely 9+6 6
=
15 14 13 12 11 10 = 7 13 11 5 = 5005 6 5 4 3 2 1
The symbol on the left is a binomial coe¢ cient. It counts the number of ways of choosing 6 things from 15 things. What does this have to do with 44
the number of numbers less than a million whose digits appear in increasing order? What we are really counting is the number of strings of digits of length 6 where the digits appear in increasing order. We can identify a four-digit number with a string starting with two zeros, so the number 1779 corresponds to the string of digits 001779. Now we come to a truly delightful move. We are going to represent the string 001779 by 9 cuts in a line of 16 dots. Here it is j j j j j j j j j We cut only once between any pair of consecutive dots, so the 9 cuts divide the 16 dots into 10 groups containing at least one dot each. Those 10 groups represent the 10 digits, in order. The number of dots in the groups are 3; 2; 1; 1; 1; 1; 3; 1; 2. If we substract 1 from each of these numbers, we get 2; 1; 0; 0; 0; 0; 0; 2; 0; 1 which we interpret as 2 zeros, 1 one, 0 twos, threes, fours, …ves, sixes, and nines, 2 sevens, and 1 nine. But that is exactly the structure of the string 001779. How do you cut the line of 16 dots to represent the string 133356? So constructing an increasing string of six digits corresponds to making 9 cuts in a line of 16 dots, that is, choosing 9 of the 15 possible places to cut. But choosing 9 things out of 15 things is the same as choosing 6 things out of 15 things: you can choose either which things to keep, or which things to leave out. In general, if we have b digits, then there are b
1+d d
increasing strings of digits of length d. Here is a short table of how many numbers (including 0) have their digits
45
appearing in increasing order: One digit : Two or fewer digits : Three or fewer digits : Four or fewer digits : Five or fewer digits : Six or fewer digits : Seven or fewer digits :
10 1 11 2 12 3 13 4 14 5 15 6 16 7
= 10 = 55 = 220 = 715 = 2002 = 5005 = 11440
Exercise 1. De…ne a Python function inc(n) that returns True if the (decimal) digits in n appear in increasing order, and False otherwise. Exercise 2. For k = 1; : : : ; 8, use your function from Exercise 1 to count how many numbers less than 10k have their digits appearing in increasing order.
7.3
Unhappy numbers
It turns out that a number n is unhappy exactly when f k (n) = 4 for some k. Certainly if f k (n) = 4, then n cannot be happy because, as we have seen, 4 is a periodic point. Starting at 4, the sequence of iterates is 4, 16, 37, 58, 89, 145, 42, 20, 4, 16, and so on— you can never get to 1. Why does every number end up at 1 or trapped in the set f4; 16; 37; 58; 89; 145; 42; 20g? How big can f (n) be if n is a four-digit number? The sum of the squares of the digits of a four-digit number is at most 4 92 , which happens when all the digits are 9. This number is 324, a three-digit number, so if n is a four-digit number, then f (n) has fewer than four digits. Similarly, if n is a …ve-digit number, then f (n) is at most 5 92 = 405, another three-digit number. In general if n is a k-digit number, that is, 10k 1 n < 10k , then
46
f (n) k 81. In fact, k 81 < 10k 1 whenever k 4. We have checked that for k = 4 and k = 5. How do we verify it for other values of k? This is a job for induction man. Suppose we have a number k for which we know that k 81 < 10k 1 . We want to show that the same is true for k + 1, that is, that (k + 1) 81 < 10k . Now we know that (k + 1) 81 = k 81 + 81 < 10k
1
+ 81
Can we say that 10k 1 + 81 < 10k ? That would verify our induction step. But 10k = 10 10k 1 so we are asking whether 81 < 9 10k 1 . Well, 81 < 9 10 = 9 102 1 , so 10k 1 + 81 is certainly less than 10k if k 2. Bingo! So if n is a number with four or more digits, then f (n) < n. Thus, starting anywhere, and iterating f , we eventually hit a three-digit number. Notice that unhappy numbers come in eight varieties depending on which of the eight numbers in f4; 16; 37; 58; 89; 145; 42; 20g they …rst run into. “Happy families are all alike; every unhappy family is unhappy in its own way.”Leo Tolstoy, Anna Karenina. Exercise 1. To check that every number ends up either at 1 or trapped in the set f4; 16; 37; 58; 89; 145; 42; 20g, it su¢ ces to check every number with three or fewer digits. That’s a pain to do by hand, but it’s easy to get Python to do. Do it.
7.4
Changing exponents and bases
There are two numbers we can change in the de…nition of f (m): the sum of the squares of the digits of m. One is the number 2 that we use because we are summing the squares of the digits. We could just as well sum the cubes of the digits, or the fourth powers of the digits. Call that number e, for exponent. For the original f , we have e = 2. It’s easy to change the recursion for f (m) so that it now computes the sum of the cubes of the digits of m. How do you do that? The other number we can change is the number 10. That is the base b for our system of representing numbers by strings of digits. If we change the number b = 10 to, say, b = 8, then the digits we get are the digits in the base-8 representation of m, that is, we are thinking of writing m in octal. The octal representation of the number 340779 is “1231453”, or 12314538 if we want to indicate that the number is written in base 8. The sum of the squares of its digits is 1 + 4 + 9 + 1 + 16 + 25 + 9 = 65 = 1018 47
and if we continue summing the squares of the digits we get 2, 4, 16 = 208 , 4 and we have run into a periodic point, 4, with period 2. Let’s examine in some detail what happens when we repeatedly sum the squares of the digits of a number in base 5. Here is the beginning of a table: 1 ! 1 2 ! 4 ! 16 = 315 ! 10 = 205 ! 4 Let f (n) denote the sum of the squares of the digits of n when we write n in base 5. Then f (1) = 1 because 1 = 15 . The number 2 is equal to 25 so f (2) = 4. The number 4 is equal to 45 , so f (4) = 16 = 315 . Now f (315 ) = 10 = 205 and f (205 ) = 4, so we are back at 4, and we have constructed the orbit 4 16 10. The next entry in our table is 3 ! 9 = 145 ! 17 = 325 ! 13 = 235 ! 13 so we have discovered another …xed point: f (13) = 13, an orbit of size 1. Continue this table up to n = 18. How many orbits do you …nd? You can easily change your program for computing f (m) to one that computes f (m; e; b), the sum of the e-th powers of the digits of m, where m is written in base b. Your …rst function f (m) was f (m; 2; 10). Exercise 1. Find the smallest number n > 1 such that n is happy in all bases 2 through 8. Exercise 2. Show that there is no number greater than 1 that is happy in all bases. Exercise 3. Show that every number is happy in bases 2 and 4. These numbers are called “happy bases”. It is claimed (http://oeis.org/A161872) that 2 and 4 are the only happy bases less than 500; 000; 000. Exercise 4. It is claimed that the greatest happy number (base 10) that has no repeated digits is 986543210. Verify that claim. Exercise 5. Find all the orbits of the functions f (m; 2; 7) and f (m; 2; 13).
8
Finding orbits
We are interested in the function f (m; e; b) that takes a number m to the sum of the e-th powers its digits when it is written in base b. We examined f (m; 2; b) in the previous section. The function f (m; e; 10) maps a positive
48
integer m to a positive integers. Such a function f gives us a discrete dynamical system. We are particularly interested in the …xed points of such a system: numbers m such that f (m) = m. The …xed points m of f (m; 3; 10) are 1, 153, 370, 371, and 407. We are also interested in periodic points which come in groups called orbits. An orbit is a …nite set S of distinct positive integers fs1 ; s2 ; : : : ; sk g so that f (si ) = si+1 , for i < k, and f (sk ) = s1 . If k = 1, then the orbit S contains exactly one number, and that number is a …xed point of f . An orbit of size 3 of the function f (m; e; 10) is f55; 250; 133g, as you can easily check by hand. It turns out that if we choose any positive integer m whatsoever, and keep applying f (m; e; b) to it, then eventually we end up in an orbit. To verify that claim, we proceed as we did for the unhappy numbers: show that f (m) < m for all su¢ ciently large values of m. If m is has k-digits when written in base b, then f (m; e; b) is at most k (b 1)e which happens when all k of the digits of m are equal to b 1, the largest digit. How many digits can the number k (b 1)e have when written in base b? If a number is less than bd , then it has at most d digits, so we would like know how large k must be to guarantee that k (b 1)e < bk 1 . However, for theoretical purposes, it is enough to know that bk 1 =k gets arbitrarly large for large values of k. That’s because all we need is for bk 1 =k eventually to be bigger than the …xed number (b 1)e . Here is a graph of the function y = 2x 1 =x
y
10 9 8 7 6 5 4 3 2 1 0 2
4
49
6
8
x
Looks like it is going o¤ to in…nity! We can use l’Hôpital’s rule to show that. Taking the derivative of the top and the bottom of 2x 1 =x we get 2x
1
ln 2
which clearly goes to in…nity. How can we …nd orbits of f ? The simplest thing to do is to choose some number n, either systematically or at random, and form the sequence n, f (n) ; f (f (n)) ; f (f (f (n))) ; : : :. There are really only two things that can happen, one of which we can detect. Either the sequence never repeats, or at some point we will generate a number that we have seen before. For all of the functions f (m; e; b), no matter what e and b are, this sequence will eventually repeat. How do we …gure out where that happens? Given a function f , we want to write a program that …nds the …rst place k such that f k (m) = f i (m) for some i < k. More precisely, we want to write a program that returns f k (m), where k is the …rst place such that f k (m) = f i (m) for some i < k. For the function f (m; 2; 10), if we start at m = 11, and repeatedly apply f , we get the sequence 11; 2; 4; 16; 37; 58; 89; 145; 42; 20; 4 so we want to return 4. To do that, we have to keep track of where we have been. We can do that using a list or using a set. We’ll do it with a set S here. At the start, we haven’t been anywhere, so S is empty. To set S equal to the empty set, we write S = set(). The standard way to generate the sequence that we want is to repeatedly set n equal to f (n). Of course we don’t want to do that forever, so we want to stop when we’ve seen n before, that is, when n is in S. The easiest way to do that is to write a while-loop: while not n in S:. We also want to update S each time we look at another value of n by putting n in S. That’s done by writing S.add(n). Those are all the ingredients— write the function. If we use a list instead of a set, we can easily get our function to return the orbit that n eventually ends up in. So now we have a list L that keeps track of where we have been. Start out by setting L = [], and write L = L + [n] instead of S.add(n). Instead of returning n when we leave the while-loop, return the slice L[ L.index(n) : ]. The function L.index(n) returns the position of the number n in the list L. The list L[ a : b ] is the slice of L that goes from position a up to, but not including, position b. The list L[ a : ] is the slice of L that goes from position a to the end of L. So L[ L.index(n) : ] is the 50
slice of the list L starting at the number n and going to the end of L. This is exactly the orbit that we end up in because n, at this point, is the …rst number we have seen twice on our journey.
9
Aliquot sequences
One very much studied discrete dynamical system is given by the function s (n) which returns the sum of the proper divisors of n. Here we include the divisor 1, even though it is rather uninteresting, but we don’t include n itself. So s (2) = 1, s (3) = 1, s (4) = 1 + 2 = 3, s (5) = 1, and s (6) = 1 + 2 + 3 = 6. Notice n is prime exactly when s (n) = 1. The number 6 is called perfect because s (6) = 6. It is a …xed point s. Technically, s (1) = 0 because 1 doesn’t have any proper divisors. I guess we could say that s (n) is the sum of the positive divisors of n that are less than n. The study of perfect numbers goes back to antiquity. A related concept is that of a pair of amicable numbers. These are distinct numbers m and n such that s (m) = n and s (n) = m. That is, the pair fm; ng is an orbit of size 2. Actually, we say that it is an orbit of period 2. The smallest amicable pair is f220; 284g. Bigger orbits are called sets of sociable numbers. There is no orbit of period 3. An example of an orbit of period 4 is f1264460; 1547860; 1727636; 1305184g. Unlike the other functions we have looked at, there is no guarantee that if we keep applying the function s, we will eventually reach a …nite orbit. In fact, this is a major unsolved problem. The …rst problematic number is 276.
10
The Collatz function
Another much studied dynamical system is given by the function f (n) =
n=2 if n is even 3n + 1 if n is odd
If you start at 1 you get the sequence 1; 4; 2; 1, an orbit of size 3. If you start at 3 you get the sequence 3; 10; 5; 16; 8; 4 ending up in the same orbit of size 3. The sequence starting at 27 is quite interesting, but also ends up in that same orbit. The Collatz conjecture is that no matter where you start, 51
you always end up in this orbit. So the conjecture is that there are no other orbits, and no sequence can wander o¤ to in…nity. It’s unlikely that we will be able to …nd any other orbits, but we can ask the question: if you start at a number n, what is the biggest number you will see if you keep applying the function f ? If you start at the number 1, the biggest number you see is 4. If you start at the number 2, the biggest number you see is 4— nothing new. If you start at the number 3, the biggest number you see is 16. A small table is start 1 2 3 4 5 6 7 8 9 biggest number encountered 4 4 16 16 16 16 52 4 52 The interesting numbers here are the ones that set new records; those are the numbers 1, 3, and 7 which set the new records 4, 16, and 52. (Try calculating by hand the largest number you get when you start with 7.) The next number to set a new record is 27 from which you eventually get to the record high of 9232. So we get a smaller table start 1 3 7 27 new record 4 16 52 9232 Each number in the …rst row reaches a value greater than that reached by any previous number (a new record). The second row shows what those values are. Project: Extend this table to include, in addition to the numbers, 1; 3; 7; 27, all record holders less than 10000. You probably don’t want to do this by hand— write a Python program instead.
11
Bulgarian solitaire
Bulgarian solitaire, a game popularized by Martin Gardner, is played with stacks of a …xed number of coins. For example, suppose you start with 10 coins divided into two stacks of 4 coins each and one stack of 2 coins. We denote this con…guration by 442. A move in the game consists of taking one coin from each stack to form a new stack. That’s it! What happens if you start with 442? You take one coin from each stack, leaving two stacks of 3 coins each and one stack of 2 coins, and you form a new stack with those 3 coins you skimmed o¤. We denote this move by 442 ! 3331. The game 52
continues 3331 ! 4222 ! 43111 ! 532 ! 4321 ! 4321 and we are stuck— a …xed point. If we start with a single stack of 9 chips, the game goes 9 ! 81 ! 72 ! 621 ! 531 ! 432 ! 3321 ! 4221 ! 4311 ! 432 and we are stuck in an orbit of size four. See http://mancala.wikia.com/wiki/Bulgarian_Solitaire Project: Write a program that plays this game. I represented a con…guration by a list L so that L [i] is the number of stacks of size i, but maybe there’s a better way to do it. Perhaps the con…guration 4311 should be represented by the list [4; 3; 1; 1] rather than the list [0; 2; 0; 1; 1] which is how I did it. Exercise 1. Show that the …xed points of Bulgarian solitaire are the con…gurations 1, 21, 321, 4321, 54321, etc. Note that there are two parts to this exercise: showing that those con…gurations are …xed points, and showing that any …xed point is one of those con…gurations. Exercise 2. Find some other orbits of size greater than one. Can you guess what the general form is?
12
The digits of n-factorial
Here are the …rst few values of n-factorial 0! 1 1! 1 2! 2 3! 6 4! 24 5! 120 6! 720 7! 5040 8! 40 320 9! 362 880 10! 3628 800 11! 39 916 800 Our …rst project is to compute how many zeros appear at the end of n!. Our second project is to compute how many zeros as digits anywhere in n!, how many ones, how many twos, and so on, up to how many nines. In the number 53
11!, the digit 0 appears twice (both at the end), the digit 1 appears once, the digit 2 never appears, and so on. Here is the number 200! 788 657 867 364 790 503 552 363 213 932 185 062 295 135 977 687 173 263 294 742 533 244 359 449 963 403 342 920 304 284 011 984 623 904 177 212 138 919 638 830 257 642 790 242 637 105 061 926 624 952 829 931 113 462 857 270 763 317 237 396 988 943 922 445 621 451 664 240 254 033 291 864 131 227 428 294 853 277 524 242 407 573 903 240 321 257 405 579 568 660 226 031 904 170 324 062 351 700 858 796 178 922 222 789 623 703 897 374 720 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 Notice that there are a whole bunch of zeros at the end. I count forty-nine of them. That means that 200! is divisible by 1049 but not by 1050 . Exercise 1. Write a program that uses that fact to calculate how many zeros there are at the end of n!. Compute the number t = n!, then keep dividing t by 10 until you can’t anymore. If you keep track of how many times you divided by 10, you will know how many zeros n! ends in. Another approach is to count how many factors of …ve there are in n!. There is one zero at the end of n! for each factor of 5. That’s because n! contains many more twos than …ves, so the number of factors of …ve will be equal to the number of factors of ten. Question: Why not use tens here? Of the numbers 1; 2; 3; : : : ; n, the number that are divisible by 5 is equal to bn=5c the ‡oor of n=5, and each of them will contribute (at least) one 5 to the product of them all, n!. The number that are divisible by 52 is equal to bn=52 c, and these will each contribute (at least) one additional 5 to the product. Continuing in this way we see that the number of 5’s in n! is equal to jnk j n k j n k + 2 + 3 + 5 5 5 where we continue the series as long as n 5k , after which all the terms are zero. Notice that this sum is approximately n
1 1 1 + 2+ 3+ 5 5 5
=
n 4
where we sum the in…nite geometric series to get 1=4. When n is 200, this estimate gives 200=4 = 50, pretty close to the actual number which is 49 as we have seen. The exact computation in this case is 200 200 200 + + = 40 + 8 + 1 = 49 5 25 125 54
In Python 2, we can realize n=5k by n/pow(5,k). Exercise 2. Write the program! A third approach in Python is to compute n! and then convert it into a string. We wouldn’t even consider this approach, except that that is the best way to do the next problem. Once we have a string s that holds the digits of n!, we can work our way from the right, starting at s [ 1], until we hit a nonzero digit. If that digit is at position m in the string, then the string has m 1 zeros at the end. Exercise 3. Write the program! The web site http://2000clicks.com/MathHelp/BasicFactorialDigitFrequency.aspx gives the digit frequencies of n! for n 500. The zeros at the end cause factorials to have more zeros than expected. Call the other zeros and digits, "inside zeros", and "inside digits". Is it true that the ratio of the inside zeros to the inside digits is approximately 1=10, and approaches this ratio in the limit as n gets large? Probably one of those impossible-to-answer questions, although we can calculate that ratio for all n less than, say, 100; 000. Zero-perfect factorials: inside zeros appear with frequency exactly 1=10. Looks like the zero-perfect factorials with n < 2000 are 15!, 24!, 54!, 146!, 326!, 643!, 732!, 1097!, 1211!, 1386!. We can also ask what are the one-perfect factorials, the two-perfect factorials, and so on. The number 15! is d-perfect for d = 0; 1; 4; 8. The numbers 146! and 732! are d-perfect for d = 0; 1, and possibly other digits. It’s not likely that we will encounter a number n so that n! is d-perfect for every digit d. If s is a Python string, then s.count(i) will return the number of occurrences of i in s. So if m = n! and s is str(m), then s.count(’0’) returns the number of occurrences of zero in n!, both inside and at the end.
12.1
Benford’s law
States that the probability that the …rst digit of a number is d is equal to log10 (1 + 1=d) = log10 (1 + d) log10 (d). So the probability that the …rst digit is 1 is log10 (2), about 30%. Test on n! and bn . See Julian Havil’s book, “Impossible?”. Here are the actual and predicted results for 2n where
55
n = 1; 2; : : : ; 2000 1 2 3 4 5 6 7 8 9 602 354 248 194 160 134 114 105 89 602 352 250 194 158 134 116 102 92 Here are the results for n! 1 2 3 4 5 6 7 8 9 591 335 250 204 161 156 107 102 94 602 352 250 194 158 134 116 102 92
13
Sequences of zeros in 2n
The …rst power of two that contains the digit 0 (in decimal notation) is 210 = 1024. Is there a power of 2 that contains two consecutive 0’s? Well, 253 = 9007 199 254 740 992 does, and it is the …rst one that does. How about three consecutive 0’s? Consider 2242 = 7067 388 259 113 537 318 333 190 002 971 674 063 309 935 587 502 475 832 486 424 805 170 479 104. Do you see the three consecutive zeros? Drawing on the work of Edgar Karst and U. Karst, Mathematics of Computation, July 1964, Julian Havil gives the following table of the …rst appearances of consecutive zeros in powers of 2: 2 3 4 5 6 7 8 53 242 377 1491 1492 6801 14007 Here is 2377 = 307 828 173 409 331 868 845 930 000 782 371 982 852 185 463 050 511 302 093 346 042 220 669 701 339 821 957 901 673 955 116 288 403 443 801 781 174 272 . Finally, here is 21491 = 68 505 199 434 441 481 928 960 132 734 923 550 768 601 593 516 271 150 047 023 043 017 169 851 270 631 488 679 017 736 106 611 268 089 166 309 388 272 338 901 170 497 165 901 308 515 144 865 310 386 727 931 343 535 071 260 408 393 094 700 786 546 061 451 067 454 457 391 289 333 260 647 178 629 423 723 325 244 889 881 619 755 782 509 111 430 765 139 535 811 541 502 291 720 957 726 164 276 777 120 274 754 519 441 816 831 362 983 266 849 142 056 649 908 740 853 890 886 083 405 397 212 467 377 035 143 021 587 233 073 571 308 500 000 341 901 085 017 693 125 848 012 770 286 553 757 194 752 360 448. You can see where the …ve consecutive zeros are, and why 21492 contains six consecutive zeros. There is a remarkable theorem to the e¤ect that there is a power of 2 containing any given number of consecutive zeros. 56
Cli¤or A. Pickover, in A passion for mathematics, page 247, says that according to Michael Beeler and William Gosper, there is at least one zero in each power of 2 between 286 = 77 371 252 455 336 267 181 195 264, and 230749014 . See item 57 of www.inwap.com/pdp10/hbaker/hakmen/hakmem.html. There is also a proof there, by Rich Schroeppel, that you can get arbitrarily many nonzero …nal digits (in fact, 1’s and 2’s). To look for patterns in the digits of a number, you can convert it to a string, and then use the Python function …nd. If s and t are strings, then s.…nd(t) will return the …rst index in the string s where the pattern t starts. So if s is the string ’23050007900’, then s.…nd(’00’) will return 4. If the pattern t does not appear in the string s, then s.…nd(t) returns 1. So s.…nd(’1’) will return 1 for this string s. To convert a number into a string, use the Python function str. For example, str(1024) returns the string ’1024’. Exercise 1. Verify that 2377 is the smallest power of 2 containing four consecutive zeros. Exercise 2. Verify that the other numbers in the table are correct. The number 14007 might take some time. Exercise 2. Explain why 21492 contains six consecutive zeros. Remember this on Columbus Day! Exercise 3. Find all powers of 2 less than 2200 that contain no zeros.
14
Ciphers
A standard method for enciphering a piece of text is to replace the letters by other letters according to a …xed scheme. One famous example is attributed to Julius Caesar. The idea was to replace the letter a by the letter d, the letter b by the letter e, the letter c by the letter f , and so on until the letter z is replaced by the letter c. The scheme can be summarized in the following table a b c d e f g h i j k l m n o p q r s t u v w x y z d e f g h i j k l m n o p q r s t u v w x y z a b c where the letters in the second row are substituted for the letters in the …rst row. So the word “caesar”would become “fdhvu”. If we think of the letters of the alphabet as being the numbers 0; 1; 2; : : : ; 25, this amounts to replacing the number n by the number n + 3 (mod 26).
57
More brie‡y, we can think of the plain alphabet as being the string "abcdefghijklmnopqrstuvwxyz" and what we need to do is to specify a cipher alphabet which is some permutation of these 26 letters. In the Caesar cipher case, we choose the cipher alphabet to be the string "defghijklmnopqrstuvwxyzabc". Suppose p is the plain alphabet and c is the cipher alphabet. How do we encrypt a message t? We want to form a new string r which is the encrypted message. The i-th character in the message t is t [i]. We need to know the position j of t [i] in the plain alphabet p. (Remember that positions start at 0.) Then we can set r [i] equal to c [j]. There is a Python function associated with the string p that does just that. It is called p.…nd(). If we write p.…nd(’u’), we will get the position of the …rst occurrence of the letter u in the string p. If the letter u does not appear in the string p, then we get the number 1. So we want to set r[i] = c[j] where j = p.…nd(t[i]). To decipher a message, we interchange the roles of p and c. There is a quick way to generate a cipher alphabet from a word, called a keyword. It’s much easier to remember a keyword than to remember a whole cipher alphabet. Here is how you generate a cipher alphabet from the phrase “boca raton”. First you eliminate the space and all the duplicate letters, so you are left with “bocartn”. Then you form the following table, with the letters bocartn at the top, and the rest of the alphabet written in rows underneath: b o c a r t n d e f g h i j k l m p q s u v w x y z Finally, you read o¤ the cipher alphabet by going down each column: bdkvoelwcfmxagpyrhqztisnju Exercise 1. What happens when you take the keyword to be the oneletter word “a”? The one-letter word “b”? The one-letter word “z”? Exercise 2. Develop a formula, like n+3 (mod 26) for the Caesar cipher, for how to encipher using the two-letter keyword “ab”?
58
15
Stu¤
What are the possible last two digits of a power of 2? Here are the …rst few powers of 2 modulo 100: 2; 4; 8; 16; 32; 64; 28; 56; 12; 24; 48; 96; 92; 84; 68; 36; 72; 44; 88; 76; 52; 4 Multiplying by 2 modulo 100 is a discrete dynamical system. We have just found one of the orbits, namely: 4; 8; 16; 32; 64; 28; 56; 12; 24; 48; 96; 92; 84; 68; 36; 72; 44; 88; 76; 52 This orbit has size 20. The numbers in the orbit are all periodic points of period 20. Notice that these numbers are all divisible by 4— it is not di¢ cult to show that this must be the case. However not all two-digit numbers that are divisible by 4 appear in this list. For example, the number 40 doesn’t appear in this list. Does that mean that a power of two cannot end in the digits 40?
59
View more...
Comments