Programming Praxis put out the previous had us composing already existing PRNGs).
The first function is the middle square PRNG. Basically, you start with a seed with an even number of digits and then repeatedly square it and return the middle digits.
Here I have a function that will take any suitable seed and generate a sequence of psuedorandom numbers from it:
; middle square PRNG: square the seed and take the middle digits
(define (make-middle-square n)
(lambda ()
(let ([digits (inexact->exact (ceiling (log n 10)))])
(let ([res (mod (div (* n n)
(expt 10 (/ digits 2))) (expt 10 digits))])
(set! n res)
res))))
An example of running it (using the same seed from the Wikipedia page):
~ (define middle-square (make-middle-square 675248))
~ (middle-square)
959861
~ (middle-square)
333139
~ (middle-square)
981593
~ (middle-square)
524817
~ (middle-square)
432883
The second example is perhaps even simpler. This time you start with any odd seed and apply the relation xn+1 = 65539 * xn mod 231:
; randu PRNG: x_n+1 = 65539 * x_n mod 2^31 (assume x_0 is odd)
(define make-randu
(let ([2**31 (expt 2 31)])
(lambda (x)
(lambda ()
(let ([res (mod (* 65539 x) 2**31)])
(set! x res)
res)))))
An example run:
~ (define randu (make-randu 675249))
~ (randu)
1305471251
~ (randu)
1384299321
~ (randu)
851521963
~ (randu)
1240372481
~ (randu)
1926020867
Pretty neat. Fortunately or not, this makes me want to implement a more heavyweight PRNG now, perhaps like the Mersenne Twister. We’ll see.
If you’d like to download the full source code, you can do so here: two more random exercises source