Subtractive generator: Difference between revisions

m
used a larger font to make the formulae, italics, super- and subscripts, and symbols easier to read, added other whitespace and highlighting to the task's preamble..
m (→‎{{header|REXX}}: added/changed comments and whitespace, changed indentations, aligned statements.)
m (used a larger font to make the formulae, italics, super- and subscripts, and symbols easier to read, added other whitespace and highlighting to the task's preamble..)
Line 1:
{{task|Randomness}}
A ''subtractive generator'' calculates a sequence of [[random number generator|random numbers]], where each number is congruent to the subtraction of two previous numbers from the sequence. <br>
The formula is
 
A ''subtractive generator'' calculates a sequence of [[random number generator|random numbers]], &nbsp; where each number is congruent to the subtraction of two previous numbers from the sequence. <br>
* <math>r_n = r_{(n - i)} - r_{(n - j)} \pmod m</math>
<br>The formula is
* <big><big><math> r_n = r_{(n - i)} - r_{(n - j)} \pmod m </math></big></big>
 
for some fixed values of &nbsp; <big><big><math> i, </math></big></big> &nbsp; <big><big><math> j, </math></big></big> &nbsp; and &nbsp; <big><big><math> m</math></big></big>, &nbsp; all positive integers.
for some fixed values of <math>i</math>, <math>j</math> and <math>m</math>, all positive integers. Supposing that <math>i > j</math>, then the state of this generator is the list of the previous numbers from <math>r_{n - i}</math> to <math>r_{n - 1}</math>. Many states generate uniform random integers from <math>0</math> to <math>m - 1</math>, but some states are bad. A state, filled with zeros, generates only zeros. If <math>m</math> is even, then a state, filled with even numbers, generates only even numbers. More generally, if <math>f</math> is a factor of <math>m</math>, then a state, filled with multiples of <math>f</math>, generates only multiples of <math>f</math>.
 
Supposing that &nbsp; <big><big><math>i > j</math></big></big>, &nbsp; then the state of this generator is the list of the previous numbers from &nbsp; <big><big><math> r_{n-i} </math></big></big> &nbsp; to &nbsp; <big><big><math> r_{n - 1}</math></big></big>.
All subtractive generators have some weaknesses. The formula correlates <math>r_n</math>, <math>r_{(n - i)}</math> and <math>r_{(n - j)}</math>; these three numbers are not independent, as true random numbers would be. Anyone who observes <math>i</math> consecutive numbers can predict the next numbers, so the generator is not cryptographically secure. The authors of ''Freeciv'' ([http://svn.gna.org/viewcvs/freeciv/trunk/utility/rand.c?view=markup utility/rand.c]) and ''xpat2'' (src/testit2.c) knew another problem: the low bits are less random than the high bits.
 
forMany somestates fixedgenerate valuesuniform ofrandom integers from &nbsp; <mathbig>i</mathbig>, <math>j</math> and0 </math>m</mathbig>, all positive integers. Supposing that <math>i > j</mathbig>, then&nbsp; theto state of this generator is the list of the previous numbers from&nbsp; <mathbig>r_{n - i}</mathbig> to <math>r_{n m- 1}</math>. Many states generate uniform random integers from <math>0</mathbig> to <math>m - 1</mathbig>, &nbsp; but some states are bad. &nbsp; A state, filled with zeros, generates only zeros. &nbsp; If &nbsp; <big><big><math> m </math></big></big> &nbsp; is even, &nbsp; then a state, filled with even numbers, generates only even numbers. &nbsp; More generally, &nbsp; if &nbsp; <big><big><math> f </math></big></big> &nbsp; is a factor of &nbsp; <big><big><math> m</math></big></big>, &nbsp; then a state, filled with multiples of &nbsp; <big><big><math> f</math></big></big>, generates only multiples of &nbsp; <big><big><math> f</math></big></big>.
The subtractive generator has a better reputation than the [[linear congruential generator]], perhaps because it holds more state. A subtractive generator might never multiply numbers: this helps where multiplication is slow. A subtractive generator might also avoid division: the value of <math>r_{(n - i)} - r_{(n - j)}</math> is always between <math>-m</math> and <math>m</math>, so a program only needs to add <math>m</math> to negative numbers.
 
All subtractive generators have some weaknesses. &nbsp; The formula correlates &nbsp; <big><big><math> r_n</math></big></big>, &nbsp; <big><big><math> r_{(n-i)} </math></big></big> &nbsp; and &nbsp; <big><big><math> r_{(n-j)}</math></big></big>; &nbsp; these three numbers are not independent, as true random numbers would be.
The choice of <math>i</math> and <math>j</math> affects the period of the generator. A popular choice is <math>i = 55</math> and <math>j = 24</math>, so the formula is
 
Anyone who observes &nbsp; <big><big><math> i </math></big></big> &nbsp; consecutive numbers can predict the next numbers, so the generator is not cryptographically secure.
* <math>r_n = r_{(n - 55)} - r_{(n - 24)} \pmod m</math>
 
The authors of ''Freeciv'' &nbsp; ([http://svn.gna.org/viewcvs/freeciv/trunk/utility/rand.c?view=markup utility/rand.c]) &nbsp; and ''xpat2'' (src/testit2.c) &nbsp; knew another problem: &nbsp; the low bits are less random than the high bits.
The subtractive generator from ''xpat2'' uses
 
The subtractive generator has a better reputation than the &nbsp; [[linear congruential generator]], &nbsp; perhaps because it holds more state. &nbsp; A subtractive generator might never multiply numbers: &nbsp; this helps where multiplication is slow. &nbsp; A subtractive generator might also avoid division: &nbsp; the value of &nbsp; <big><big><math> r_{(n - i)} - r_{(n - j)} </math></big></big> &nbsp; is always between &nbsp; <big><big><math> -m </math></big></big> and <big><big><math> m </math></big></big>, &nbsp; so a program only needs to add &nbsp; <big><big><math> m </math></big></big> &nbsp; to negative numbers.
* <math>r_n = r_{(n - 55)} - r_{(n - 24)} \pmod{10^9}</math>
 
The choice of &nbsp; <big><big><math> i </math></big></big> &nbsp; and &nbsp; <big><big><math> j </math></big></big> &nbsp; affects the period of the generator.
The implementation is by J. Bentley and comes from program_tools/universal.c of [ftp://dimacs.rutgers.edu/pub/netflow/ the DIMACS (netflow) archive] at Rutgers University. It credits Knuth, [[wp:The Art of Computer Programming|''TAOCP'']], Volume 2, Section 3.2.2 (Algorithm A).
 
A popular choice is &nbsp; <big><big><math> i = 55 </math></big></big> &nbsp; and &nbsp; <big><big><math> j = 24</math></big></big>, &nbsp; so the formula is:
* <big><big><math> r_n = r_{(n - 55)} - r_{(n - 24)} \pmod m </math></big></big>
The subtractive generator from ''xpat2'' uses:
* <big><big><math> r_n = r_{(n - 55)} - r_{(n - 24)} \pmod{10^9} </math></big></big>
 
The implementation is by J. Bentley and comes from program_tools/universal.c of &nbsp; [ftp://dimacs.rutgers.edu/pub/netflow/ the DIMACS (netflow) archive] at Rutgers University. &nbsp; It credits Knuth, &nbsp; [[wp:The Art of Computer Programming|''TAOCP'']], Volume 2, Section 3.2.2 &nbsp; (Algorithm A).
 
Bentley uses this clever algorithm to seed the generator.
 
# Start with a single &nbsp; <big><big><math> seed </math></big></big> &nbsp; in range &nbsp; <big><big><math> 0 </math></big></big> &nbsp; to &nbsp; <big><big><math> 10^9 - 1</math></big></big>.
# Set &nbsp; <big><big><math> s_0 = seed</math></big></big> &nbsp; and &nbsp; <big><big><math> s_1 = 1</math>.</big></big> &nbsp; The inclusion of &nbsp; <big><big><math> s_1 = 1 </math></big></big> &nbsp; avoids some bad states &nbsp; (like all zeros, or all multiples of 10).
# Compute &nbsp; <big><big><math> s_2, s_3, ..., s_{54} </math></big></big> &nbsp; using the subtractive formula &nbsp; <big><big><math> s_n = s_{(n - 2)} - s_{(n - 1)} \pmod{10^9} </math>.</big></big>
# Reorder these &nbsp; '''55''' &nbsp; values so &nbsp; <big><big><math> r_0 = s_{34}</math></big></big>, &nbsp; <big><big><math> r_1 = s_{13}</math>,</big></big> &nbsp; <big><big><math> r_2 = s_{47}</math></big></big>, ..., &nbsp; <big><big><math> r_n = s_{(34 * (n + 1) \pmod{55})}</math>.</big></big>
#* This is the same order as &nbsp; <big><big><math> s_0 = r_{54}</math></big></big>, &nbsp; <big><big><math> s_1 = r_{33}</math></big></big>, &nbsp; <big><big><math> s_2 = r_{12}</math></big></big>, ..., &nbsp; <big><big><math> s_n = r_{((34 * n) - 1 \pmod{55})}</math>.</big></big>
#* This rearrangement exploits how '''34''' and '''55''' are relatively prime.
# Compute the next '''165''' values &nbsp; <big><big><math> r_{55}</math></big></big> &nbsp; to &nbsp; <big><big><math> r_{219}</math></big></big>. &nbsp; Store the last '''55''' values.
 
<br>
This generator yields the sequence &nbsp; <big><big><math> r_{220}</math></big></big>, &nbsp; <big><big><math> r_{221}</math></big></big>, &nbsp; <big><big><math> r_{222} </math></big></big> &nbsp; and so on. &nbsp; For example, if the seed is &nbsp; '''292929''', &nbsp; then the sequence begins with &nbsp; <big><big><math> r_{220} = 467478574</math></big></big>, &nbsp; <big><big><math> r_{221} = 512932792</math></big></big>, &nbsp; <big><big><math> r_{222} = 539453717</math></big></big>. &nbsp; By starting at &nbsp; <big><big><math> r_{220}</math></big></big>, &nbsp; this generator avoids a bias from the first numbers of the sequence. &nbsp; This generator must store the last 55 numbers of the sequence, so to compute the next &nbsp; <big><big><math> r_n</math></big></big>. &nbsp; Any array or list would work; a &nbsp; [[ring buffer]] &nbsp; is ideal but not necessary.
 
Implement a subtractive generator that replicates the sequences from ''xpat2''.
<br><br>
 
=={{header|Ada}}==