;; 3-6-in-class.scm ;; ;; edited version ; did in class together ;; ;; Exercise 3.6: It is useful to be able to reset a random-number ;; generator to produce a sequence starting from a given value. Design ;; a new rand procedure that is called with an argument that is either ;; the symbol generate or the symbol reset and behaves as follows: ;; ;; (rand ’generate) : produce a new random number ;; ;; ((rand ’reset)〈new-value〉) : resets the internal state variable ;; to the designated〈new-value〉. ;; ;; Thus, by resetting the state, one can generate repeatable ;; sequences. These are very handy to have when testing and debugging ;; programs that use random numbers. ;; ;; ----------------------------------------------------------- ;; ;; Guile scheme has a built-in (random max) that gives a pseudo-random ;; from 0 to max-1. ;; ;; First I'll construct something similar that has an explicit seed ;; in the argument list, similar to the discussion in the next, ;; using the mod arithmetic approach mentioned in the text, and ;; the discussion at en.wikipedia.org/wiki/Linear_congruential_generator . ;; I choose these values : ;; x[n+1] = (A * x[n] + C) mod M ;; M = 2**32 , A = 1103515245 , C = 1013904223 (from Numerical Recipes) (define (next-rand seed) ;; return the next pseudo-random in the sequence, 0 <= seed < 2**32 (let ((A 1103515245) (C 1013904223) (M 4294967296)) ;; 2**32 i.e. 32 bits (modulo (+ (* A seed) C) M))) (define (next-rand-list seed max how-many) ;; return a list of how-many positive pseudo-randoms less than max. ;; (This version used (next-rand seed) and therefore needs an explicit seed.) (if (< how-many 0) '() (let ((next-seed (next-rand seed))) (cons (modulo next-seed max) (next-rand-list next-seed max (- how-many 1)))))) ;; So let's see some pseudo-randoms, eh? (let ((seed 1234567) (how-many 20) (max 10)) (display (next-rand-list seed max how-many)) (newline)) ;; That gives : (8 3 4 5 6 1 6 9 0 7 4 3 2 9 2 1 6 9 4 7 0) ... which looks OK. ;; ---------------------------- ;; ;; Now use that starting point to do what the question asks, ;; replacing (rand-next seed) with (rand 'generate) (define (make-rand) (let ((seed 1234567 )) (lambda (what) (cond ((eq? what 'generate) (begin (set! seed (next-rand seed)) seed)) ((eq? what 'reset) (lambda (new-seed) (set! seed new-seed))) (else "OOPS"))))) (define rand (make-rand)) ;; create this "rand" function (printf "some randoms : \n") (display (rand 'generate)) (newline) (display (rand 'generate)) (newline) (display (rand 'generate)) (newline) (display (rand 'generate)) (newline) (printf "reset : \n") ((rand 'reset) 100000) (display (rand 'generate)) (newline) (display (rand 'generate)) (newline) (display (rand 'generate)) (newline) (display (rand 'generate)) (newline) (printf "reset : \n") ((rand 'reset) 100000) (display (rand 'generate)) (newline) (display (rand 'generate)) (newline) (display (rand 'generate)) (newline) (display (rand 'generate)) (newline) ;; Running this gives ;; $ scheme 3-6-in-class.scm ;; (8 3 4 5 6 1 6 9 0 7 4 3 2 9 2 1 6 9 4 7 0) ;; some randoms : ;; 893086938 ;; 2357377073 ;; 3407629884 ;; 364546795 ;; reset : ;; 1943668095 ;; after reset, sequence starts here ;; 2099903602 ;; 2221288425 ;; 3699811220 ;; reset : ;; 1943668095 ;; ... and does same again after reset ;; 2099903602 ;; 2221288425 ;; 3699811220 ;;