<< Previous exercise (3.81) | Index | Next exercise (4.1) >>
Meteorgan's solution uses the monte-carlo method with variables passed and failed. Following solution doesn't uses these and relies solely on streams.
(define (add-streams s1 s2) (stream-map + s1 s2)) (define ones (cons-stream 1.0 ones)) (define integers (cons-stream 1.0 (add-streams ones integers))) (define (random-stream lo hi) (define (random-in-range low high) (let ((range (- high low))) (+ low (random range)))) (cons-stream (random-in-range lo hi) (random-stream lo hi))) (define (estimate-integral p x1 x2 y1 y2) (define throw-results (stream-map (lambda (x) (if (eq? x true) 1.0 0)) (stream-map p (random-stream x1 x2) (random-stream y1 y2)))) (define successful-throws (cons-stream (stream-car throw-results) (add-streams (stream-cdr throw-results) successful-throws))) (define (get-area probability) (* probability (abs (* (- y2 y1) (- x2 x1))))) (stream-map get-area (stream-map / successful-throws integers)))
Isn't producing random numbers the predicate's job? Doesn't the following simple definition of estimate-integral suffice?
(define (estimate-integral P x1 x2 y1 y2)
(let ((width (- x2 x1))
(height (- y2 y1)))
(let ((area (* width height)))
(scale-stream (monte-carlo P 0 0) area))))
Uses the random-in-range procedure previously defined in the book.
(define (random-in-range low high) (let ((range (- high low))) (+ low (random range)))) (define (rand-range-stream low high) (cons-stream (random-in-range low high) (rand-range-stream low high))) (define (experiment-stream x1 x2 y1 y2 radius) (stream-map (lambda (x) (> radius x)) (add-streams (stream-map square (rand-range-stream x1 x2)) (stream-map square (rand-range-stream y1 y2))))) (define pi-est-stream (scale-stream (monte-carlo (experiment-stream -1.0 1.0 -1.0 1.0 1.0) 0 0) 4.0)) (exact->inexact (stream-ref pi-est-stream 50000)) ;; ~3.1429
Similar solution to meteorgan's. Requires random-in-range from Excercise 3.5 and monte-carlo from the beginning of section 3.5.5.
(define (randoms-ranged low high) (cons-stream (random-in-range low high) (randoms-ranged low high))) (define (integral-estimates P x1 x2 y1 y2) (define point-in-integral-stream (stream-map P (randoms-ranged x1 x2) (randoms-ranged y1 y2))) (monte-carlo point-in-integral-stream 0 0)) (define (in-unit-circle? x y) (<= (+ (expt (- x 0.5) 2) (expt (- y 0.5) 2)) (expt 0.5 2))) (define pi-integral-estimates (stream-map (lambda (area) (/ area (* 0.5 0.5))) (integral-estimates in-unit-circle? 0.0 1.0 0.0 1.0)))
LisScheSic
If we use sicp-ex-3.5 as the lib, then the above can be simplified although sharing the same basic ideas.
Assume to use x3v's implementation:
(define (estimate-integral p x1 x2 y1 y2) (let ((area (* (- x2 x1) (- y2 y1))) (randoms (stream-map (lambda (ignore) (p x1 x2 y1 y2 1)) ones))) (scale-stream (monte-carlo (stream-map p randoms) 0 0) area)))