4.37 Exercise 4.37

Consider the two following procedures for computing Pythagorean triples with high and low bounds:

(define (a-pythagorean-triple-between low high)
  (let ((i (an-integer-between low high)))
    (let ((j (an-integer-between i high)))
      (let ((k (an-integer-between j high)))
        (require (= (+ (* i i) (* j j)) (* k k)))
        (list i j k)))))
(define (a-pythagorean-triple-between low high)
  (let ((i (an-integer-between low high))
        (hsq (* high high)))
    (let ((j (an-integer-between i high)))
      (let ((ksq (+ (* i i) (* j j))))
        (require (>= hsq ksq))
        (let ((k (sqrt ksq)))
          (require (integer? k))
          (list i j k))))))

The former method is naive and straightforward, iterating through all of the possibilities for i, j, and k and testing whether the equality holds. This is very inefficient, requiring on the order of O(n^3) operations.

The alternative solution is more clever. First, it acts on the fact that it isn’t necessary to test more than a single potential k value after i and j are fixed – there’s only one sum to their squares, and the square root of that is either an integer or not. Doing this cuts a power of n off of the time complexity.

However, in order for this to work, you need to know when to stop testing values. However, this is also easily done – we know that the maximum value of k cannot be greater than the square root of the high bound. Alternatively, as expressed in the algorithm above, k^2 cannot be greater than high^2. (My only complaint about the above is that I would calculate hsq before i). Then, all that needs to be done is checking whether the potential k^2 values are no greater than this upper bound.

We can see that the second algorithm does test every valid i and j, and that this means that all possible triples with i and j within bounds are checked. We can also see that no possible triples outside of the bounds will be considered – any value of k such that k^2 is greater than high^2 is not accepted. Therefore, we can trust that the second algorithm is correct, while also being significantly more efficient than the first.