3.65 Exercise 3.65
We can define the terms of the series equivalent
to the natural logarithm of 2 as follows:
(define (ln-summands n) | (cons-stream (/ 1.0 n) | (stream-map - (ln-summands (+ n 1))))) |
|
We can then define an initial, non-accelerated version
of the series converting on the value ln 2 as follows:
(define ln-stream (partial-sums (ln-summands 1))) |
Using Euler acceleration with euler-transform, we
can define an accelerated version of this stream as follows:
(define (euler-transform s) | (let ((s0 (stream-ref s 0)) | (s1 (stream-ref s 1)) | (s2 (stream-ref s 2))) | (cons-stream (- s2 (/ (square (- s2 s1)) | (+ s0 (* -2 s1) s2))) | (euler-transform (stream-cdr s))))) |
|
(define ln-stream++ (euler-transform ln-stream)) |
And using tableau acceleration, we can define a "super"-accelerated
stream:
(define (make-tableau transform s) | (cons-stream s | (make-tableau transform | (transform s)))) |
|
(define (accelerated-sequence transform s) | (stream-map stream-car | (make-tableau transform s))) |
|
(define ln-stream# (accelerated-sequence euler-transform ln-stream)) |
If we want to test how quickly these streams converge on the
correct value of ln 2, we can write a simple procedure,
analogous to stream-limit, that will count the number
of stream values that need to be processed until two
consecutive values are within a certain tolerance of the
correct value.
(define (stream-values-until-precise s correct tolerance) | (define (count i last rest) | (let ((r (stream-car rest))) | (if (< (abs (- correct (average last r))) tolerance) | i | (count (+ i 1) r (stream-cdr rest))))) | (count 2 (stream-car s) (stream-cdr s))) |
|
The initial value passed to count is 2 because, in
the case that the first two values of the stream are within
tolerance bounds, we would say that 2 stream values
have been consumed before reaching this precision. In other
words, the minimal number of stream values that need to be
examined before the last two are within tolerance is, of
course, 2. (It is merely a convention that the value
i denotes the number of values that will have been
processed after that iteration of count).
Noting that scheme already defines a fuction log for
finding the natural logarithm, we can then ask how many
values it takes to reach the correct value within a small
tolerance (disclosure: which is kept somewhat large to keep
the page generation time low) as follows:
> (define correct (log 2)) |
> (define tolerance 1e-07) |
> (stream-values-until-precise ln-stream correct tolerance) |
1582 |
> (stream-values-until-precise ln-stream++ correct tolerance) |
36 |
> (stream-values-until-precise ln-stream# correct tolerance) |
6 |