Skip to content

Commit 6d636c2

Browse files
author
David Brady
committed
Added Knuth & Lewis' version of Park & Miller's LCRNG to Generating Predictable Random Numbers
1 parent e07bbed commit 6d636c2

File tree

1 file changed

+64
-3
lines changed

1 file changed

+64
-3
lines changed

chapters/math/generating-predictable-random-numbers.textile

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,74 @@ You need to generate a random number in a certain range, but you also need to be
1010

1111
h2. Solution
1212

13-
Write your own random number generator. There are a LOT of ways to do this. Here's a simple one.
13+
Write your own random number generator. There are a LOT of ways to do this. Here's a simple one. _This generator is +ABSOLUTELY NOT+ acceptable for cryptographic purposes!_
1414

1515
{% highlight coffeescript %}
16-
# TODO: write simple linear PRNG
16+
class Rand
17+
# if created without a seed, uses current time as seed
18+
constructor: (@seed) ->
19+
# Knuth and Lewis' improvements to Park and Miller's LCPRNG
20+
@multiplier = 1664525
21+
@modulo = 4294967296 # 2**32-1;
22+
@offset = 1013904223
23+
unless @seed? && 0 <= seed < @modulo
24+
@seed = (new Date().valueOf() * new Date().getMilliseconds()) % @modulo
25+
26+
# sets new seed value
27+
seed: (seed) ->
28+
@seed = seed
29+
30+
# return a random integer 0 <= n < @modulo
31+
randn:
32+
# new_seed = (a * seed + c) % m
33+
@seed = (@multiplier*@seed + @offset) % @modulo
34+
35+
# return a random float 0 <= f < 1.0
36+
rand: ->
37+
this.randn() / @modulo
38+
39+
# return a random int 0 <= f < n
40+
randi: (n) ->
41+
Math.floor(this.rand() * n)
42+
43+
r = new Rand 0
44+
r.randn().toString(16)
45+
# => "3c6ef35f"
46+
47+
r.randn().toString(16)
48+
# => "47502932"
49+
50+
r.randn().toString(16)
51+
# => "d1ccf6e9"
52+
53+
r.randn().toString(16)
54+
# => "aaf95334"
55+
56+
r.randn().toString(16)
57+
# => "6252e503"
58+
59+
r.randn().toString(16)
60+
# => "9f2ec686"
1761
{% endhighlight %}
1862

1963
h2. Discussion
2064

21-
JavaScript and CoffeeScript do not provide a seedable random number generator. Writing your own will be an exercise in trading off the amount of randomness with the simplicity of the generator. A full discussion of randomness is beyond the scope of this cookbook; for further reading consult Donald Knuths _The Art of Computer Programming_, Volume II.
65+
JavaScript and CoffeeScript do not provide a seedable random number generator. Writing your own will be an exercise in trading off the amount of randomness with the simplicity of the generator. A full discussion of randomness is beyond the scope of this cookbook; for further reading consult Donald Knuth's _The Art of Computer Programming_, Volume II, Chapter 3, "Random Numbers", and _Numerical Recipes in C_, 2nd Edition, Chapter 7, "Random Numbers".
66+
67+
A brief explanation of this random number generator is in order, however. It is a Linear Congruential Pseudorandom Number Generator. LCPRNG's operate on the mathematical formula <tt>I<sub>j+1</sub> = (aI<sub>j</sub>+c) % m</tt>, where a is the multiplier, c is the addition offset, and m is the modulus.
68+
Each time a random number is requested, a very large multiplication and addition are performed&mdash;"very large" relative to the key space&mdash;and the resulting number is modulused back down into the keyspace.
69+
70+
This generator has a period of 2<sup>32</sup>. It is absolutely unacceptable for cryptographic purposes, but for most simple randomness requirements it is quite adequate. randn() will traverse the entire keyspace before repeating itself, and the next number is determined by the previous one.
71+
72+
If you want to tinker with this generator, you are _strongly_ encouraged to read Chapter 3 of Knuth's _The Art of Computer Programming_. Random number generation is VERY easy to screw up, and Knuth explains how to tell a good RNG from a bad one.
73+
74+
Avoid the temptation to modulus the output of this generator. If you need an integer range, use division. Linear Congruential generators are very nonrandom in their lower bits. This one in particular always generates an odd number from an even seed, and vice versa. So if you need a random 0 or 1, do NOT use
75+
76+
{% highlight coffeescript %}
77+
# NOT random! Do not do this!
78+
r.randn() % 2
79+
{% endhighlight %}
80+
81+
because you will most definitely not get random digits. Use <tt>r.randi(2)</tt> instead.
82+
2283

0 commit comments

Comments
 (0)