SICP section 1.2.3

June 28th, 2007 at 5:50 am

In this section the authors provide the standard introduction to orders of growth (big-Oh notation) and give a few simple examples of formulas and their growth orders.

Exercise 1.14

The tree is pretty big, so I’ll refrain from drawing it. However, it is quite clear how it goes. Obviously, the deepest path in the tree happens when the result is the sum in all pennies. So the space is O(n) for n that is the amount we want to change.

Figuring out the time complexity here is much more challenging, because the recursion formula is hard to solve analytically. Initially I thought it’s exponential, but Thomas Morgan convinced me that it is polynomial, somewhere in the order of O(N^5). If you have a proof, please let me know.

Note that similarly to the recursive Fibonacci, there is a lot of repetitiveness – we’ll be solving the same problem over an over again in different sub-branches of the tree. Memoization can improve matters here a lot.

Exercise 1.15

Here is the code rewritten in CL, along with some printing to find out how many times p is called:

(defun cube (x)
  (* x x x))

(defun p (x)
  (format t "p ~f~%" x)
  (-  (* 3 x)
      (* 4 (cube x))))

(defun sine (angle)
  (if (not (> (abs angle) 0.1))
    angle
    (p (sine (/ angle 3.0)))))

By running (sine 12.15) we can see that p is called 5 times. How does the call sequence look:

(sine 12.15)
(p (sine 4.05))
(p (p (sine 1.35)))
(p (p (p (sine 0.45))))
(p (p (p (p (sine 0.15)))))
(p (p (p (p (p (sine 0.05))))))
(p (p (p (p (p 0.05)))))
...

Clearly, p is called for as long as the division of the angle by 3 stays above 0.1; therefore, the runtime of this function is logarithmic, more specifically O(log3(n)). The space is logarithmic as well, because this is a linear recursion where each computation is a single recursive call (as opposed to tree recursion, where each computation splits to 2 or more calls).

Related posts:

  1. SICP section 1.2.6
  2. SICP section 1.2.2
  3. SICP section 2.3.3
  4. SICP section 1.3.1
  5. SICP section 2.2.2

7 Responses to “SICP section 1.2.3”

  1. liweiNo Gravatar Says:

    “Clearly, p is called for as long as the division of the angle by 3 stays above 1.0;”

    0.1

  2. elibenNo Gravatar Says:

    liwei:
    Thanks for noticing. I’ve fixed the typo

  3. ThomasNo Gravatar Says:

    Dear Eli,

    I’m studying Exercise 1.14, and I wonder if it’s true that cc grows exponentially in number of steps. I found that the number of steps can be computed by the cc-steps procedure below.


    (define (sigma m n fun)
    (define (iterate sum m n)
    (if (< n m)
    sum
    (iterate (+ sum (fun n)) m (- n 1))))
    (iterate 0 m (floor n)))


    (define (cc-steps amount kinds-of-coins)
    (if (= kinds-of-coins 1)
    (+ 1 (* amount 2))
    (+ 1
    (ceiling (/ amount (first-denomination kinds-of-coins)))
    (sigma 1
    (ceiling (/ amount (first-denomination kinds-of-coins)))
    (lambda (k)
    (cc-steps
    (- amount (* (first-denomination kinds-of-coins)
    (- k 1)))
    (- kinds-of-coins 1)))))))

    This amounts to nested summations, one fewer than the number of kinds of coins; so with five kinds of coins, there are four summations. This is how it looks expanded out in Maxima code:


    f(x) := (1
    + ceiling(x/50)
    + sum(1
    + ceiling((x-50*(i-1))/25)
    + sum(1
    + ceiling((x-50*(i-1)-25*(j-1))/10)
    + sum(1
    + ceiling((x-50*(i-1)-25*(j-1)-10*(k-1))/5)
    + sum(1
    + 2*(x-50*(i-1)-25*(j-1)-10*(k-1)-5*(l-1)),
    l,
    1,
    ceiling((x-50*(i-1)-25*(j-1)-10*(k-1))/5)),
    k,
    1,
    ceiling((x-50*(i-1)-25*(j-1))/10)),
    j,
    1,
    ceiling((x-50*(i-1))/25)),
    i,
    1,
    ceiling(x/50)));

    X is in the term of the innermost summation and also in the upper bound, so ignoring everything but x, x is added x times, which is x^2. All four summations then result in x^5, or x to the power of the number of kinds of coins. This is polynomial growth.

    I plotted x^5 against cc-steps with x from 0 to 100, from 0 to 500, and from 0 to 1000, and found that the curves matched more closely each time (I can send you JPEGs if you send me your email address).

    Please let me know if you see I’m making a mistake somewhere, and thanks for this great blog!

    Thomas

  4. YingshengNo Gravatar Says:

    Hi, Eli
    I’m studying Exercise 1.14 and I think the time complexity could be calculated as follow:

    let f(n) = count-change(n, 1), and then we can get the f(n) by
    f(n) = f(n- 1) + count-change(n, 0) + 1
    = f (n -1) + 1 + 1 = f(n-1) + 2
    = f(n – 2) + 2 + 2
    …..
    = f(n – n) + 2 * n
    = 2 * n + 1
    time complexity is O(n)

    and then we let the g(n) = count-change(n, 2), x = ceil(n / 5), we can get
    the g(n) by

    g(n) = f (n) + g(n – 5) + 1
    = f(n) + f(n – 5) + g(n – 5 * 2) + 1 + 1
    …..
    = f(n) + f(n – 5) + … f(n – 5 * (x – 1)) + g(n – 5 * x) + x

    as the time complexity of f(n) is O(n) , and the approximation of x is
    n/5, so time complexity of g(n) is O(n) * n/5 + n/5, which is O(n^2).

    By using the same way, we can get the complexity of count-change(n, k)
    is n^k (k <=5)

  5. TonyNo Gravatar Says:

    I have posted a solution, with proof, to Ex 1.14 here:
    http://sicp.org.ua/sicp/Exercise1-14?action=AttachFile&do=view&target=countingcoins.pdf

    There are some minor errors in that file, but I don’t think they affect the outcome.

  6. IvoNo Gravatar Says:

    I believe Thomas is right. I do not have a rigorous proof, but I believe the following reasoning is easy enough to follow:

    There is one way to make change with only 1 cent coins. This solution takes n steps to find, so it’s time complexity is O(n).

    There are n/5 ways to make change for an amount n with 1 and 5 cent coins, because you can use between 1 and n/5 5 cent coins and add an appropriate number of 1 cent coins to obtain n. On average, an amount of n/2 remains for the 1 cent coins, meaning the algorithm takes ~n/2 steps to find that solution (for large n, the 1 cent steps vastly outnumber the 5 cent ones).

    This then makes for a time complexity of O(n^2).

    For other two cent combinations, the same reasoning holds:
    There are ~n/10 ways to make changes with 1 and 10 cent coins. On average, these again take ~n/2 steps to find, again making for a time complexity of O(n^2).

    There are ~n/10 ways to make changes with 5 and 10 cent coins. On average, these take ~(n/5)/2 steps to find, again making for a time complexity of O(n^2).

    Now for the interesting bit:
    How many ways are there to make change with 1, 5 and 10 cent coins?
    There are n/10 possibilities for the number of 10 cent coins. On average, the remaining amount that needs to be changed is n/2. There are n/5 ways to fill an amount with 1 and 5 cent coins, as per our earlier calculation. That makes for n/10*(n/5)/2 combinations.

    Each of these combinations leaves, on average, n/2 to be filled by 1 cent coins, so again n/2 steps are needed by the algorithm. Consequently, the time complexity of this solution is O(n^3).

    This argument can be extended for any number of different coins and coin sizes. As a result, the time complexity of the algorithm for this particular set of coins is O(n^5)

  7. allenNo Gravatar Says:

    Hi,Eli

    Here’s a solution about Ex 1.14.

    First,a defination of the time complexity,’ how many times the procedure does under the worst situation .”

    So,maybe like this,for 5 different kinds of coins,each will take n times under the worst situation .And then the time complexity is n^5.

    Obviously,it’s not rigorous.But that’s what I’ve learned and known.

    Please let me known if it’s wrong.Thanks so much.