Here are some of the links I've found interesting enough to tweet or retweet in that past several weeks.
Programming
A beautiful obfuscated Pi calculator
Programming language trends of 2009
Tweetable game of life in MATLAB
Factorization of RSA768
Calculating Sines
Science
Leonardo da Vinci's resume
Richard Dawkins: Growing up in the universe
Richard Hamming: You and your research
Math
A quick little puzzle (in probability)
Euler Book Prize (A list to watch in the future. Since the site isn't updated for 2010 yet, the winner was Euler's Gem by David S. Richeson.)
A cryptic math advertisement
Miscellaneous
Succed Blog
RockYou.com's 20 most common passwords
50 Books Every Geek Should Read
Saturday, January 30, 2010
SICP Exercise 1.21: Smallest Divisor
From SICP section 1.2.6 Example: Testing for Primality
Exercise 1.21 asks us to use the
The
This procedure makes use of the
The
We can find the solutions to the exercise by simply running the code in an interpreter.
As you can see, the first two numbers are prime because they are their own smallest divisor, but the third is divisible by 7.
Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
Exercise 1.21 asks us to use the
smallest-divisor
procedure to find the smallest divisor of each of the following numbers: 199, 1999, 19999.The
smallest-divisor
procedure was given earlier in the section.(define (smallest-divisor n)
(find-divisor n 2))
(define (find-divisor n test-divisor)
(cond ((> (square test-divisor) n) n)
((divides? test-divisor n) test-divisor)
(else (find-divisor n (+ test-divisor 1)))))
(define (divides? a b)
(= (remainder b a) 0))
This procedure makes use of the
square
procedure that was defined earlier. You'll need to include it if you want to run the code in an interpreter.(define (square x)
(* x x))
The
smallest-divisor
procedure finds the smallest integral divisor (greater than 1) of a given number n in a straightforward way, by testing to see if n is divisible by each integer from 2 to √n. Since the number of steps is between 1 and √n, the order of growth of the algorithm is O(√n).We can find the solutions to the exercise by simply running the code in an interpreter.
> (smallest-divisor 199)
199
> (smallest-divisor 1999)
1999
> (smallest-divisor 19999)
7
As you can see, the first two numbers are prime because they are their own smallest divisor, but the third is divisible by 7.
Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
Labels:
programming,
scheme,
sicp
Tuesday, January 26, 2010
SICP Exercise 1.20: GCD
From SICP section 1.2.5 Greatest Common Divisors
Exercise 1.20 asks us to consider the following iterative procedure that uses Euclid's Algorithm to comput the GCD:
We're asked to illustrate the process generated by this procedure when using normal-order and applicative-order evaluation rules to evaluate
We learned the rules for both applicative-order and normal-order evaluation back in SICP section 1.1.5 The Substitution Model for Procedure Application. We learned that under normal-order evaluation rules, the interpreter fully expands a procedure before reducing it. Operand expressions are substituted for parameters until an expression involving only primitive operators is reached. Under applicative-order rules, arguments are evaluated before operators are applied. This can often avoid multiple unnecessary evaluations of the same expression, which is one of the reasons why Lisp uses applicative-order evaluation.
In section 1.1.6 Conditional Expressions and Predicates (see exercise 1.5) we're told to assume that the evaluation rule for the special form
Now let's put all of this together to illustrate both processes for
Normal-order evaluation - fully expand and then reduce.
At this point both of the nested
Here again, multiple nested
There are seven nested
Finally, we can evaluate these four
Applicative-order evaluation - evaluate arguments and then apply operands. This one is a little bit easier to follow. With each substitution, we just evaluate the operands that we need before applying the operators at each step.
As you can see, using applicative-order evaluation,
Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
Exercise 1.20 asks us to consider the following iterative procedure that uses Euclid's Algorithm to comput the GCD:
(define (gcd a b)
(if (= b 0)
a
(gcd b (remainder a b))))
We're asked to illustrate the process generated by this procedure when using normal-order and applicative-order evaluation rules to evaluate
(gcd 206 40)
. How many remainder
operations are actually performed using each evaluation model?We learned the rules for both applicative-order and normal-order evaluation back in SICP section 1.1.5 The Substitution Model for Procedure Application. We learned that under normal-order evaluation rules, the interpreter fully expands a procedure before reducing it. Operand expressions are substituted for parameters until an expression involving only primitive operators is reached. Under applicative-order rules, arguments are evaluated before operators are applied. This can often avoid multiple unnecessary evaluations of the same expression, which is one of the reasons why Lisp uses applicative-order evaluation.
In section 1.1.6 Conditional Expressions and Predicates (see exercise 1.5) we're told to assume that the evaluation rule for the special form
if
is the same whether we use normal or applicative order evaluation. "The predicate expression is evaluated first, and the result determines whether to evaluate the consequent or the alternative expression." We'll continue using this assumption until we're told otherwise.Now let's put all of this together to illustrate both processes for
(gcd 206 40)
.Normal-order evaluation - fully expand and then reduce.
(gcd 206 40)
(if (= 40 0)
206
(gcd 40 (remainder 206 40)))
(gcd 40 (remainder 206 40))
(if (= (remainder 206 40) 0)
40
(gcd (remainder 206 40) (remainder 40 (remainder 206 40))))
(if (= 6 0) ;; 1 remainder evaluated
40
(gcd (remainder 206 40) (remainder 40 (remainder 206 40))))
(gcd (remainder 206 40) (remainder 40 (remainder 206 40)))
(if (= (remainder 40 (remainder 206 40)) 0)
(remainder 206 40)
(gcd (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))))
At this point both of the nested
remainder
operations that were substituted in for b
in the (= b 0)
procedure need to be evaluated. I'll combine these and show them as one step.(if (= 4 0) ;; 2 remainders evaluated
(remainder 206 40)
(gcd (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))))
(gcd (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40))))
(if (= (remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))
0)
(remainder 40 (remainder 206 40))
(gcd (remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))
(remainder (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40))))))
Here again, multiple nested
remainder
operations that were substituted in for b
in the (= b 0)
procedure need to be evaluated. I'll combine all four and show them as one step.(if (= 2 0) ;; 4 remainders evaluated
(remainder 40 (remainder 206 40))
(gcd (remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))
(remainder (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40))))))
(gcd (remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))
(remainder (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))))
(if (= (remainder (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))) 0)
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))
(gcd (remainder (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40))))
(remainder (remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))
(remainder (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40
(remainder 206 40)))))))
There are seven nested
remainder
operations to evaluate at this point.(if (= 0 0) ;; 7 remainders evaluated
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))
(gcd (remainder (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40))))
(remainder (remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))
(remainder (remainder 40 (remainder 206 40))
(remainder (remainder 206 40)
(remainder 40
(remainder 206
40)))))))
(remainder (remainder 206 40)
(remainder 40 (remainder 206 40)))
Finally, we can evaluate these four
remainder
operations to come up with the answer (GCD) and the total.2 ;; 18 total remainders evaluated
Applicative-order evaluation - evaluate arguments and then apply operands. This one is a little bit easier to follow. With each substitution, we just evaluate the operands that we need before applying the operators at each step.
(gcd 206 40)
(if (= 40 0)
206
(gcd 40 (remainder 206 40))))
(gcd 40 (remainder 206 40))
(gcd 40 6) ;; 1st remainder evaluated
(if (= 6 0)
40
(gcd 6 (remainder 40 6)))
(gcd 6 (remainder 40 6))
(gcd 6 4) ;; 2nd remainder evaluated
(if (= 4 0)
6
(gcd 4 (remainder 6 4)))
(gcd 4 (remainder 6 4))
(gcd 4 2) ;; 3rd remainder evaluated
(if (= 2 0)
4
(gcd 2 (remainder 4 2)))
(gcd 2 (remainder 4 2))
(gcd 2 0) ;; 4th remainder evaluated
(if (= 0 0)
2
(gcd 0 (remainder 2 0)))
2
As you can see, using applicative-order evaluation,
remainder
was only evaluated four times, compared to 18 times using normal-order evaluation.Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
Labels:
programming,
scheme,
sicp
Saturday, January 23, 2010
Unsolved: Odd Perfect Numbers
A perfect number is a number that is the sum of its proper divisors (i.e., including 1 but excluding itself).
For example, the smallest perfect number is 6.
The next two perfect numbers are
See sequence A000396 in OEIS for a list of the first ten perfect numbers.
On a related note, a number that is smaller than the sum of its proper divisors is an abundant number, while a number greater than the sum of its proper divisors is called deficient. The smallest abundant number is 12, whose proper divisors sum to 16.
All of the perfect numbers that have been discovered so far are even.
If there is an odd perfect number, we already know a lot about it. It must be at least 300 digits long, with at least 75 prime factors, at least 9 of them distinct. Its largest prime factor must be greater than 100,000,000. Its second largest prime factor is greater than 10,000, and its third largest is greater than 100.
For example, the smallest perfect number is 6.
1 + 2 + 3 = 6
The next two perfect numbers are
1 + 2 + 4 + 7 + 14 = 28
1 + 2 + 4 + 8 + 16 + 31 + 62 + 124 + 248 = 496
1 + 2 + 4 + 8 + 16 + 31 + 62 + 124 + 248 = 496
See sequence A000396 in OEIS for a list of the first ten perfect numbers.
On a related note, a number that is smaller than the sum of its proper divisors is an abundant number, while a number greater than the sum of its proper divisors is called deficient. The smallest abundant number is 12, whose proper divisors sum to 16.
All of the perfect numbers that have been discovered so far are even.
The problem is to find an odd perfect number, or prove that no odd perfect numbers exist.
If there is an odd perfect number, we already know a lot about it. It must be at least 300 digits long, with at least 75 prime factors, at least 9 of them distinct. Its largest prime factor must be greater than 100,000,000. Its second largest prime factor is greater than 10,000, and its third largest is greater than 100.
Labels:
math,
perfect numbers,
unsolved
Friday, January 22, 2010
SICP Exercise 1.19: Computing Fibonacci numbers
From SICP section 1.2.4 Exponentiation
Exercise 1.19 asks us to complete a procedure for computing Fibonacci numbers in a logarithmic number of steps. The following code is given:
We're reminded of the transformation of the state variables a and b in the original fib-iter procedure from section 1.2.2: a ← a + b and b ← a. If these state changes are labeled transformation T, then applying T repeatedly for n iterations starting with a = 1 and b = 0 produces the pair a = Fib(n + 1) and b = Fib(n). So the Fibonacci numbers are produced by the nth power of the transformation T, or Tn, starting with the pair (1, 0).
We are then asked to consider the family of transformations Tpq which transforms the pair (a, b) according to the following rules:
We can verify by quick substitution that the original transformation T is just a special case of Tpq, where p = 0 and q = 1.
We are asked to show that if we apply Tpq twice, the effect is the same as using a single transformation Tp'q' of the same form, and compute p' and q' in terms of p and q. This will give us an explicit way to square these transformations, which we can use to compute Tn using successive squaring, just like the fast-expt procedure from exercise 1.16.
We can apply Tpq twice by defining new variables and using substitution. Let's define a1 and b1 as the results of applying transformation Tpq once
The next step is to define a2 and b2 and apply the tranformation a second time, this time using a1 and b1 in place of a and b.
Now that we have a system of equations defined, we can use substitution on our way to simplifying.
The second equation is shorter, so it should be easier to manipulate. Remember, we're trying to find p' and q', so we need to rewrite the equation to fit the form
where p' and q' can be computed in terms of q and p.
From this we can see that p' and q' can be computed using the following equations:
Manipulating the equation for a2 in the same way, we can verify those results. This time we're trying to fit the form
The groupings required for this manipulation are made even easier by the fact that we now already know the formulas for p' and q'.
Now that we've verified the formulas for p' and q' in terms of p and q, we can use them to complete the procedure we were given.
You can test several known values in an interpreter to verify that this actually works.
Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
Exercise 1.19 asks us to complete a procedure for computing Fibonacci numbers in a logarithmic number of steps. The following code is given:
(define (fib n)
(fib-iter 1 0 0 1 n))
(define (fib-iter a b p q count)
(cond ((= count 0) b)
((even? count)
(fib-iter a
b
<??> ; compute p'
<??> ; compute q'
(/ count 2)))
(else (fib-iter (+ (* b q) (* a q) (* a p))
(+ (* b p) (* a q))
p
q
(- count 1)))))
We're reminded of the transformation of the state variables a and b in the original fib-iter procedure from section 1.2.2: a ← a + b and b ← a. If these state changes are labeled transformation T, then applying T repeatedly for n iterations starting with a = 1 and b = 0 produces the pair a = Fib(n + 1) and b = Fib(n). So the Fibonacci numbers are produced by the nth power of the transformation T, or Tn, starting with the pair (1, 0).
We are then asked to consider the family of transformations Tpq which transforms the pair (a, b) according to the following rules:
a ← bq + aq + ap
b ← bp + aq
b ← bp + aq
We can verify by quick substitution that the original transformation T is just a special case of Tpq, where p = 0 and q = 1.
a ← b(1) + a(1) + a(0)
a ← b + a
b ← b(0) + a(1)
b ← a
a ← b + a
b ← b(0) + a(1)
b ← a
We are asked to show that if we apply Tpq twice, the effect is the same as using a single transformation Tp'q' of the same form, and compute p' and q' in terms of p and q. This will give us an explicit way to square these transformations, which we can use to compute Tn using successive squaring, just like the fast-expt procedure from exercise 1.16.
We can apply Tpq twice by defining new variables and using substitution. Let's define a1 and b1 as the results of applying transformation Tpq once
a1 = bq + aq + ap
b1 = bp + aq
b1 = bp + aq
The next step is to define a2 and b2 and apply the tranformation a second time, this time using a1 and b1 in place of a and b.
a2 = b1q + a1q + a1p
b2 = b1p + a1q
b2 = b1p + a1q
Now that we have a system of equations defined, we can use substitution on our way to simplifying.
a2 = (bp + aq)q + (bq + aq + ap)q + (bq + aq + ap)p
b2 = (bp + aq)p + (bq + aq + ap)q
b2 = (bp + aq)p + (bq + aq + ap)q
The second equation is shorter, so it should be easier to manipulate. Remember, we're trying to find p' and q', so we need to rewrite the equation to fit the form
b2 = bp' + aq'
where p' and q' can be computed in terms of q and p.
b2 = (bp + aq)p + (bq + aq + ap)q
= (bpp + apq) + (bqq + aqq + apq)
= bpp + apq + bqq + aqq + apq
= (bpp + bqq) + (2apq + aqq)
= b(pp + qq) + a(2qp + qq)
= (bpp + apq) + (bqq + aqq + apq)
= bpp + apq + bqq + aqq + apq
= (bpp + bqq) + (2apq + aqq)
= b(pp + qq) + a(2qp + qq)
From this we can see that p' and q' can be computed using the following equations:
p' = p2 + q2
q' = 2pq + q2
q' = 2pq + q2
Manipulating the equation for a2 in the same way, we can verify those results. This time we're trying to fit the form
a2 = bq' + aq' + ap'
The groupings required for this manipulation are made even easier by the fact that we now already know the formulas for p' and q'.
a2 = (bp + aq)q + (bq + aq + ap)q + (bq + aq + ap)p
= (bpq + aqq) + (bqq + aqq + apq) + (bpq + apq + app)
= bpq + aqq + bqq + aqq + apq + bpq + apq + app
= (bpq + bpq + bqq) + (apq + apq + aqq) + (app + aqq)
= b(pq + pq + qq) + a(pq + pq + qq) + a(pp + qq)
= b(2pq + qq) + a(2pq + qq) + a(pp + qq)
= (bpq + aqq) + (bqq + aqq + apq) + (bpq + apq + app)
= bpq + aqq + bqq + aqq + apq + bpq + apq + app
= (bpq + bpq + bqq) + (apq + apq + aqq) + (app + aqq)
= b(pq + pq + qq) + a(pq + pq + qq) + a(pp + qq)
= b(2pq + qq) + a(2pq + qq) + a(pp + qq)
Now that we've verified the formulas for p' and q' in terms of p and q, we can use them to complete the procedure we were given.
(define (fib n)
(fib-iter 1 0 0 1 n))
(define (fib-iter a b p q count)
(cond ((= count 0) b)
((even? count)
(fib-iter a
b
(+ (* p p) (* q q)) ; compute p'
(+ (* 2 p q) (* q q)) ; compute q'
(/ count 2)))
(else (fib-iter (+ (* b q) (* a q) (* a p))
(+ (* b p) (* a q))
p
q
(- count 1)))))
You can test several known values in an interpreter to verify that this actually works.
> (fib 0)
0
> (fib 1)
1
> (fib 2)
1
> (fib 3)
2
> (fib 5)
5
> (fib 10)
55
> (fib 20)
6765
Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
Labels:
programming,
scheme,
sicp
Thursday, January 14, 2010
SICP Exercise 1.18: Iterative multiplication
From SICP section 1.2.4 Exponentiation
Exercise 1.18 asks us to use the results from the two previous exercises (1.16 and 1.17) to devise a procedure that generates an iterative process for multiplying two integers in terms of adding, doubling and halving, and which uses a logarithmic number of steps.
The key idea from exercise 1.16 was to keep an additional state variable
Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
Exercise 1.18 asks us to use the results from the two previous exercises (1.16 and 1.17) to devise a procedure that generates an iterative process for multiplying two integers in terms of adding, doubling and halving, and which uses a logarithmic number of steps.
The key idea from exercise 1.16 was to keep an additional state variable
a
, and manipulate the state transition so that the product (a * bn) remained unchanged. We can modify our solution to exercise 1.17 to use the same idea. Since we're now dealing with multiplication instead of exponentiation, the invariant quantity will be (a * b + p) where a
and b
are the two operands, and p
will be our state variable. Initially p
will be 0, but by the end of the iterative process it will hold the product (a * b).(define (even? n)
(= (remainder n 2) 0))
(define (double x)
(+ x x))
(define (halve x)
(/ x 2))
(define (mult-iter a b p)
(cond ((= 0 b) p)
((even? b) (mult-iter (double a) (halve b) p))
(else (mult-iter a (- b 1) (+ a p)))))
(define (mult a b)
(mult-iter a b 0))
Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
Labels:
programming,
scheme,
sicp
Wednesday, January 13, 2010
SICP Exercise 1.17: Multiplication by repeated addition
From SICP section 1.2.4 Exponentiation
Exercise 1.17 asks us to design a multiplication procedure analogous to
We'll also use the same
The following multiplication procedure that takes a linear number of steps is given:
This procedure defines multiplication in terms of the algorithm we all learned in grade school: add a to itself b times.
The exercise also makes reference to the following
This procedure makes use of the following observations:
We can define similar rules for integer multiplication.
The first rule tells us when to use our procedures
The procedure takes a logarithmic number of steps. If you double the size of the input parameter b, the procedure takes only one more step to compute the product.
Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
Exercise 1.17 asks us to design a multiplication procedure analogous to
fast-expt
that uses a logarithmic number of steps. We're told that in addition to adding, we can use procedures for doubling or halving an integer argument.(define (double x)
(+ x x))
(define (halve x)
(/ x 2))
We'll also use the same
even?
procedure we've seen before:(define (even? n)
(= (remainder n 2) 0))
The following multiplication procedure that takes a linear number of steps is given:
(define (* a b)
(if (= b 0)
0
(+ a (* a (- b 1)))))
This procedure defines multiplication in terms of the algorithm we all learned in grade school: add a to itself b times.
The exercise also makes reference to the following
fast-expt
procedure, which we can use as a guide:(define (fast-expt b n)
(cond ((= n 0) 1)
((even? n) (square (fast-expt b (/ n 2))))
(else (* b (fast-expt b (- n 1))))))
This procedure makes use of the following observations:
bn = (bn/2)2 if n is even
bn = b * bn-1 if n is odd
bn = b * bn-1 if n is odd
We can define similar rules for integer multiplication.
a * b = 2 * (a * b/2) if be is even
a * b = a + a * (b - 1) if b is odd
a * b = a + a * (b - 1) if b is odd
The first rule tells us when to use our procedures
double
and halve
. The second rule just lets us take an odd b and make it even in preparation for the next iteration. Translating these rule into a Scheme procedure give us:(define (fast-mult a b)
(cond ((= b 0) 0)
((= b 1) a)
((even? b) (double (fast-mult a (halve b))))
(else (+ a (fast-mult a (- b 1))))))
The procedure takes a logarithmic number of steps. If you double the size of the input parameter b, the procedure takes only one more step to compute the product.
Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
Labels:
programming,
scheme,
sicp
Tuesday, January 12, 2010
Guest article on Programming Praxis
I was excited to be asked to be the guest author for an article on one of my favorite programming blogs, Programming Praxis. If you're not familiar with the site, Programming Praxis provides weekly practice exercieses to "sharpen your saw" on. It was inspired in part by Project Euler, but the problems on Programming Praxis focus more on developing programming skills and usually require less advanced math than those on Project Euler.
To follow up earlier exercises on Calculating Pi and Logarithms, my article is on Calculating Sines using two different methods, the Taylor series and the Triple-angle formula. The sample solutions are written in Scheme, but readers are encouraged to submit solutions in any language they choose (see the HOWTO on posting source code to post your own solution). Since I'm still a relative newbie to Scheme (I'm currently still in chapter one of SICP), I'll be interested to see what alternate solutions you can come up with.
The article is also currently featured on Planet Scheme.
To follow up earlier exercises on Calculating Pi and Logarithms, my article is on Calculating Sines using two different methods, the Taylor series and the Triple-angle formula. The sample solutions are written in Scheme, but readers are encouraged to submit solutions in any language they choose (see the HOWTO on posting source code to post your own solution). Since I'm still a relative newbie to Scheme (I'm currently still in chapter one of SICP), I'll be interested to see what alternate solutions you can come up with.
The article is also currently featured on Planet Scheme.
Labels:
exercises,
practice,
programming,
puzzles
Monday, January 11, 2010
SICP Exercise 1.16: Fast Exponentiation
From SICP section 1.2.4 Exponentiation
Exercise 1.16 asks us to design an exponentiation procedure that evolves an iterative process using successive squaring and uses a logarithmic number of steps. A hint tells us to use the observation that (bn/2)2 = (b2)n/2 and to keep, along with the exponent
Earlier in section 1.2.4, we were given the procedure:
which tests whether an integer is even. This will come in handy again for this exercise, since we'll need to adjust
We'll also use the following simple procedure for squaring a number:
With those building blocks in place, we can define our iterative procedure.
We call the procedure
The only thing that's left to do is define a procedure that calls
Here are a few sample runs of the procedure:
You can try running the procedure with large values of
Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
Exercise 1.16 asks us to design an exponentiation procedure that evolves an iterative process using successive squaring and uses a logarithmic number of steps. A hint tells us to use the observation that (bn/2)2 = (b2)n/2 and to keep, along with the exponent
n
and base b
, an additional state variable a
, and to define the state transformation in such a way that the product a * bn
is unchanged from state to state. The value of a
should start at 1, and should contain the final answer by the end of the process.Earlier in section 1.2.4, we were given the procedure:
(define (even? n)
(= (remainder n 2) 0))
which tests whether an integer is even. This will come in handy again for this exercise, since we'll need to adjust
a
by a different amount when n
is even than when n
is odd.We'll also use the following simple procedure for squaring a number:
(define (square x)
(* x x))
With those building blocks in place, we can define our iterative procedure.
(define (expt-iter b n a)
(cond ((= n 0) a)
((even? n) (expt-iter (square b) (/ n 2) a))
(else (expt-iter b (- n 1) (* a b)))))
We call the procedure
expt-iter
with the arguments base b
, exponent n
, and the state variable a
. The first thing we do is check to see if the exponent is 0. If so, we've reached the end of the procedure and just return the value of a
. Next we check to see if n
is even. If it is, we use the observation that (bn/2)2 = (b2)n/2 to transform state information by squaring b
and dividing n
by 2. Finally, if n
is odd we transform state information by reducing n
by 1 and multiplying a
by the base b
.The only thing that's left to do is define a procedure that calls
expt-iter
with the correct initial values.(define (fast-expt b n)
(expt-iter b n 1))
Here are a few sample runs of the procedure:
> (fast-expt 2 2)
4
> (fast-expt 2 3)
8
> (fast-expt 2 10)
1024
> (fast-expt 3 3)
27
> (fast-expt 5 5)
3125
You can try running the procedure with large values of
n
to verify that it really is fast.Related:
For links to all of the SICP lecture notes and exercises that I've done so far, see The SICP Challenge.
Labels:
programming,
scheme,
sicp
Sunday, January 10, 2010
Math visualization: Multiplying Two Binomials
In my earlier post Math visualization: (x + 1)2, I showed how to draw a picture that proved the equality
An alert reader commented that (x + 1)2 is a specific instance of the binomial squared
Here's a visualization of that equality:
It turns out that the illustration can be generalized a little bit further to cover multiplying two binomials that form a rectangle (not just a perfect square).
If you want to see how this idea can be extended into the third dimension, check out Montessori World's page on the Binomial Cube.
(x + 1)2 = x2 + 2x + 1
An alert reader commented that (x + 1)2 is a specific instance of the binomial squared
(x + a)2 = x2 + 2ax + a2
Here's a visualization of that equality:
It turns out that the illustration can be generalized a little bit further to cover multiplying two binomials that form a rectangle (not just a perfect square).
(x + a)(x + b) = x2 + ax + bx + ab
If you want to see how this idea can be extended into the third dimension, check out Montessori World's page on the Binomial Cube.
Labels:
algebra,
math,
visualization
Monday, January 4, 2010
Unsolved: Twin Primes Conjecture
Prime numbers, as most school children can tell you, are those numbers that are evenly divisible by only themselves and 1. The first few primes are
We've known that there are infinitely many primes since c. 300 BC when it was proven by Euclid of Alexandria. Euclid used a very simple and elegant proof by contradiction.
Euclid's proof of the infinitude of primes
First, assume that there are a finite number of primes, p1, p2, p3, ..., pn.
Now let
That is, Q is equal to all of the primes multiplied together plus one.
By the Fundamental Theorem of Arithmetic, Q is either prime or it can be written as the product of two or more primes. However, none of the primes in our list evenly divides Q. If any prime in our list did evenly divide Q, then that same prime would also evenly divide 1, since
This contradicts the assumption that we had listed all the primes. So no matter how many primes we start with in our list, there must always be more primes. (Note that this proof does not claim that Q itself is prime, just that there must be some prime not in the initial list.)
Twin primes
Twin primes are those pairs of numers that have a difference of two, and that are both prime.
Given the simplicity of Euclid's proof of the infinitude of primes, it's tempting to hope for an equally simple proof to the Twin prime conjecture. Needless to say, such a proof has not been found.
Other facts about twin primes:
Other than (3, 5), all twin primes have the form (6n - 1, 6n + 1).
In 1919 Viggo Brun showed that the sum of the reciprocals of the twin primes converges to a definite number, now known as Brun's constant (approximately 1.902160578).
In 1994, while in the process of estimating Brun's constant by calculating the twin primes up to 1014, Thomas Nicely discovered the infamous Pentium bug.
The largest known twin primes (as of January 2010) are a pair of 100,355 digit primes with the values 65516468355 * 2333333 ± 1.
2, 3, 5, 7, 11, 13, 17...
We've known that there are infinitely many primes since c. 300 BC when it was proven by Euclid of Alexandria. Euclid used a very simple and elegant proof by contradiction.
Euclid's proof of the infinitude of primes
First, assume that there are a finite number of primes, p1, p2, p3, ..., pn.
Now let
Q = (p1 * p2 * ... * pn) + 1
That is, Q is equal to all of the primes multiplied together plus one.
By the Fundamental Theorem of Arithmetic, Q is either prime or it can be written as the product of two or more primes. However, none of the primes in our list evenly divides Q. If any prime in our list did evenly divide Q, then that same prime would also evenly divide 1, since
Q - (p1 * p2 * ... * pn) = 1
This contradicts the assumption that we had listed all the primes. So no matter how many primes we start with in our list, there must always be more primes. (Note that this proof does not claim that Q itself is prime, just that there must be some prime not in the initial list.)
Twin primes
Twin primes are those pairs of numers that have a difference of two, and that are both prime.
3, 5
5, 7
11, 13
17, 19
...
5, 7
11, 13
17, 19
...
The Twin prime conjecture, which dates back to the 18th century, simply states that there are infinitely many twin primes.
Given the simplicity of Euclid's proof of the infinitude of primes, it's tempting to hope for an equally simple proof to the Twin prime conjecture. Needless to say, such a proof has not been found.
Other facts about twin primes:
Other than (3, 5), all twin primes have the form (6n - 1, 6n + 1).
In 1919 Viggo Brun showed that the sum of the reciprocals of the twin primes converges to a definite number, now known as Brun's constant (approximately 1.902160578).
In 1994, while in the process of estimating Brun's constant by calculating the twin primes up to 1014, Thomas Nicely discovered the infamous Pentium bug.
The largest known twin primes (as of January 2010) are a pair of 100,355 digit primes with the values 65516468355 * 2333333 ± 1.
Subscribe to:
Posts (Atom)