Jim Reeds sent me this about the Go random number generator. He's given
me permission to post it here provided that I point out that these
comments were written off-the-cuff, 25 years or so
after the events, at the end of a tiring day, without any
serious attempt to verify the facts.
> I am the co-author, together with Don Mitchell. Actually, we wrote
> it first for the then-current version of UNIX (v9, or v10) and it
> was picked up by Ken Thompson for use in Plan 9. From there I
> suppose it flowed into Go naturally. I don't actually know when Don
> and I did this. Definitely before 1997.
>
> We never documented it. Our value-added to what's described in
> Knuth is the seeding. Ken had noticed that a naive seeding of an
> earlier lag-17 generator gave biased results in the early output of
> the RNG, and liked the idea of running the RNG a long time to bring
> it into a "steady state" of randomness. So that's what we did: use
> a more-or-less perfunctory LCG to nudge the presumably OK-looking
> rng_cooked[] vector.
>
> (Ken used some earlier RNG in the 'fortunes' program, which, at
> login-time, typed a randomly selected motto from a file of one-liner
> zingers. It was seeded with, let's say, the pid or the output of
> time(0). He saw repeated fortunes more often than he expected, and
> discovered that the effect of the seed on the RNG he was using did
> not really kick in in a serious way until thousands and thousands of
> calls later. Hence the concern.)
So I think your comments are spot on.
I'd like to put a little more documentation in rng.go referencing
Knuth / wikipedia for the generator part and a description of what the
cooked numbers are and how the seeding works, something like this
diff -r abd51e52924a src/pkg/math/rand/rng.go
--- a/src/pkg/math/rand/rng.go Thu Feb 27 01:45:22 2014 -0800
+++ b/src/pkg/math/rand/rng.go Thu Feb 27 17:23:02 2014 +0000
@@ -26,6 +26,10 @@
// cooked random numbers
// the state of the rng
// after 780e10 iterations
+ //
+ // These are used as a set of clean random numbers which are
+ // perturbed by the seeding algorithm into a new state for the
+ // generator.
rng_cooked [_LEN]int64 = [...]int64{
5041579894721019882, 4646389086726545243, 1395769623340756751,
5333664234075297259,
2875692520355975054, 9033628115061424579, 7143218595135194537,
4812947590706362721,
@@ -201,6 +205,8 @@
// Seed uses the provided seed value to initialize the generator to a
deterministic state.
func (rng *rngSource) Seed(seed int64) {
+ // This uses a Linear Congruential Generator to perturb the
+ // cooked random numbers into a new state for the generator.
rng.tap = 0
rng.feed = _LEN - _TAP
@@ -229,6 +235,10 @@
}
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
+//
+// The random numbers are generated using an Additive Lagged Fibonacci
+// Generator as described in Knuth: Art of Computer Programming Vol 2,
+// with a sequence length of at least 2**607.
func (rng *rngSource) Int63() int64 {
rng.tap--
if rng.tap < 0 {