Sign in Join
Wiki copytemporary

Marsaglia's pseudo random number generators: what changed

Revision 1 to 2. Removed lines have a minus sign; added lines have a plus sign.

OldNewLine
1-<figure>
2-<img src="fpc_source_logo.png" title="fpc_source_logo.png" />
3-<figcaption>fpc_source_logo.png</figcaption>
4-</figure>
1+![](/wiki-images/8/84/Fpc_source_logo.png)
52
63## Marsaglia's pseudo random number generators
74
85Although Free Pascal has a reasonably good pseudo random number generator (PRNG), a [[A simple implementation of the Mersenne twister|Mersenne Twister]], it is rather slow.
96
107In 1999 (and 2003), Professor George Marsaglia described a set of PRNGs with good properties that are much faster and often just as good. He was kind enough to provide sourcecode - in C - and a description of each. The XorShift PRNG from the 2003 paper is added as well. Some of these PRNGs, either stand-alone or in combination, have over time been proven to be equal or superior to either Delphi's LNG or even Free Pascal's Mersenne twister. Notably SWR, XorShift and combined e.g. SWB+KISS which has a period of 2^7700 and passes all tests for randomness.
118
129Here we present a class that encapsulates these PRNGs for 32 bit random values with a short explanation. The class contains the following PRNGs with Marsaglia's comments from his usenet post. It is extremely fast.
1310
1411Marsaglia describes them as follows:
1512
1613### Multiply with carry
1714
1815`     The MWC generator concatenates two 16-bit multiply-`\
1916`     with-carry generators, x(n)=36969x(n-1)+carry,`\
2017`     y(n)=18000y(n-1)+carry mod 2^16, has period about`\
2118`     2^60 and seems to pass all tests of randomness. A`\
2219`     favorite stand-alone generator---faster than KISS,`\
2320`     which contains it.  `
2421
2522### fibonaci
2623
2724`     FIB is the classical Fibonacci sequence`\
2825`     x(n)=x(n-1)+x(n-2),but taken modulo 2^32.`\
2926`     Its period is 3*2^31 if one of its two seeds is odd`\
3027`     and not 1 mod 8. It has little worth as a RNG by`\
3128`     itself, but provides a simple and fast component for`\
3229`     use in combination generators.`\
3330`     The classical Fibonacci sequence mod 2^32 from FIB`\
3431`     fails several tests. It is not suitable for use by`\
3532`     itself, but is quite suitable for combining with`\
3633`     other generators.`
3734
3835### Congruential generator
3936
4037`     CONG is a congruential generator with the widely used 69069`\
4138`     multiplier: x(n)=69069x(n-1)+1234567. It has period`\
4239`     2^32. The leading half of its 32 bits seem to pass`\
4340`     tests, but bits in the last half are too regular.`\
4441`     The last half of the bits of CONG are too regular,`\
4542`     and it fails tests for which those bits play a`\
4643`     significant role. CONG+FIB will also have too much`\
4744`     regularity in trailing bits, as each does. But keep`\
4845`     in mind that it is a rare application for which`\
4946`     the trailing bits play a significant role. CONG`\
5047`     is one of the most widely used generators of the`\
5148`     last 30 years, as it was the system generator for`\
5249`     VAX and was incorporated in several popular`\
5350`     software packages, all seemingly without complaint.`\
5451`     (note: this is about the same as Delphi uses)`
5552
5653### four lagged Fibonaci
5754
5855`     LFIB4 is an extension of what (Marsaglia) have previously`\
5956`     defined as a lagged Fibonacci generator:`\
6057`     x(n)=x(n-r) op x(n-s), with the x's in a finite`\
6158`     set over which there is a binary operation op, such`\
6259`     as +,- on integers mod 2^32, * on odd such integers,`\
6360`     exclusive-or(xor) on binary vectors. Except for`\
6461`     those using multiplication, lagged Fibonacci`\
6562`     generators fail various tests of randomness, unless`\
6663`     the lags are very long. (See SWB below).`\
6764`     To see if more than two lags would serve to overcome`\
6865`     the problems of 2-lag generators using +,- or xor, I`\
6966`     have developed the 4-lag generator LFIB4 using`\
7067`     addition: x(n)=x(n-256)+x(n-179)+x(n-119)+x(n-55)`\
7168`     mod 2^32. Its period is 2^31*(2^256-1), about 2^287,`\
7269`     and it seems to pass all tests---in particular,`\
7370`     those of the kind for which 2-lag generators using`\
7471`     +,-,xor seem to fail. For even more confidence in`\
7572`     its suitability, LFIB4 can be combined with KISS,`\
7673`     with a resulting period of about 2^410: just use`\
7774`     (KISS+LFIB4) in any Pascal expression.`
7875
7976### 3-shift-register generator
8077
8178`     SHR3 is a 3-shift-register generator with period`\
8279`     2^32-1. It uses y(n)=y(n-1)(I+L^17)(I+R^13)(I+L^5),`\
8380`     with the y's viewed as binary vectors, L the 32x32`\
8481`     binary matrix that shifts a vector left 1, and R its`\
8582`     transpose. SHR3 seems to pass all except those`\
8683`     related to the binary rank test, since 32 successive`\
8784`     values, as binary vectors, must be linearly`\
8885`     independent, while 32 successive truly random 32-bit`\
8986`     integers, viewed as binary vectors, will be linearly`\
9087`     independent only about 29% of the time.`\
9188`     (note: this is an ancestor of XORSHIFT (2003) and very fast)`
9289
9390### Subtract with borrow
9491
9592`     SWB is a subtract-with-borrow generator that I`\
9693`     developed to give a simple method for producing`\
9794`     extremely long periods:`\
9895`     x(n)=x(n-222)-x(n-237)- borrow mod 2^32.`\
9996`     The 'borrow' is 0, or set to 1 if computing x(n-1)`\
10097`     caused overflow in 32-bit integer arithmetic. This`\
10198`     generator has a very long period, 2^7098(2^480-1),`\
10299`     about 2^7578. It seems to pass all tests of`\
103100`     randomness, except for the Birthday Spacings test,`\
104101`     which it fails badly, as do all lagged Fibonacci`\
105102`     generators using +,- or xor. I would suggest`\
106103`     combining SWB with KISS, MWC, SHR3, or CONG.`\
107104`     KISS+SWB has period >2^7700 and is highly`\
108105`     recommended.`\
109106`     Subtract-with-borrow has the same local behaviour`\
110107`     as lagged Fibonacci using +,-,xor---the borrow`\
111108`     merely provides a much longer period.`\
112109`     SWB fails the birthday spacings test, as do all`\
113110`     lagged Fibonacci and other generators that merely`\
114111`     combine two previous values by means of =,- or xor.`\
115112`     Those failures are for a particular case: m=512`\
116113`     birthdays in a year of n=2^24 days. There are`\
117114`     choices of m and n for which lags >1000 will also`\
118115`     fail the test. A reasonable precaution is to always`\
119116`     combine a 2-lag Fibonacci or SWB generator with`\
120117`     another kind of generator, unless the generator uses`\
121118`     *, for which a very satisfactory sequence of odd`\
122119`     32-bit integers results.`
123120
124121### Keep it simple sir
125122
126123`     The KISS generator, (Keep It Simple Stupid), is`\
127124`     designed to combine the two multiply-with-carry`\
128125`     generators in MWC with the 3-shift register SHR3 and`\
129126`     the congruential generator CONG, using addition and`\
130127`     exclusive-or. Period about 2^123.`\
131128`     It is one of (Marsaglia's) favorite generators.`
132129
133130### XorShift
134131
135132This was not in the original post, it was only published in 2003, but since it is a similar algorithm and it is of importance for its speed and properties.\
136133I feel it is warranted to include it here.\
137134It is similar to the SHR3 PRNG and is described in detail in the pdf you find in the link below.
138135
139136### Implementation
140137
141138The class is a fully static sealed class so you do not have to instantiate it or derive from it. If you use just one of the PRNGs it is easy to factor it out. Note that several Prng's maintain state:
142139
143140Here I have implemented it as a static class, but it is also possible to write them as a function with writable typed constants. I would recommend the static class approach, though, since calling the class constructor can reset the PRNG, Something that is not (easily) possible with the functional approach unless you would use global variables or double the state fields. Note that if you assign the output to a signed integer, you will get signed result, if needed.
144141
145142``` pascal
146143unit uMarsaglia;
147144{ author: Thaddy de Koning, based on the original C sourcecode in the original post by George Marsaglia }
148145{ http://www.ciphersbyritter.com/NEWS4/RANDC.HTM#369B5E30.65A55FD1@stat.fsu.edu }
149146{$mode objfpc}
150147interface
151148
152149type
153150 { It is not meant to be extended, since it is based on a single article so I sealed the class }
154151 TMarsagliaPrngs = class sealed
155152 strict private
156153 {static variables:}
157154 class var T: array [0..255] of dword;
158155 class var a,b,v,w,x,y,z,bro,jcong,jsr:dword;
159156 class var c:byte;
160157 class function wnew:dword;inline;static;
161158 class function znew:dword;inline;static;
162159 public
163160 { You can also call the create explicitly to reset the static
164161 variables.}
165162 class constructor create;
166163 class procedure settable(const i1,i2,i3,i4,i5,i6:dword);static;
167164 class procedure Randomize;inline;static;
168165 class function MWC:dword;inline;static;
169166 class function SHR3:dword;inline;static;
170167 class function CONG:dword;inline;static;
171168 class function FIB:dword;inline;static;
172169 class function KISS:dword;inline;static;
173170 class function LFIB4:dword;inline;static;
174171 class function SWB:dword;inline;static;
175172 // From XSorShift Prng's, 2003
176173 class function XOS:dword;inline;static;
177174 end;
178175
179176 { a shorthand alias: }
180177 Prng = type TMarsagliaPrngs;
181178
182179 { Because many simulations call for uniform
183180 random variables in 0<x<1 or -1<x<1, here's a utility function.
184181 Using Signed = false will provide a random single in range (0,1),
185182 while Signed true will provide one in range (-1,1).
186183 Simply feed it the output of one of the Prng's}
187184 function ScaleToFloat(const value:dword; Signed:Boolean=true):single;inline;
188185
189186
190187implementation
191188
192189 class function TMarsagliaPrngs.znew:dword;inline;static;
193190 begin
194191 z:=36969*(z and 65535)+(z >> 16);
195192 Result:= z;
196193 end;
197194
198195 class function TMarsagliaPrngs.wnew:dword;inline;static;
199196 begin
200197 w:=18000*(w and 65535)+(w >> 16);
201198 Result := w;
202199 end;
203200
204201
205202 class constructor TMarsagliaPrngs.create;
206203 begin
207204 a:=224466889; b:=7584631;c:=0;v:=2463534242;w:=521288629;x:=0;y:=0;
208205 z:=362436069;jsr:=123456789; jcong:=380116160;
209206 settable(12345,65435,34221,12345,9983651,95746118);
210207 end;
211208
212209 { Use random seeds to reset z,w,jsr,jcong,a,b, and the table t[256]}
213210 class procedure TMarsagliaPrngs.settable(const i1,i2,i3,i4,i5,i6:dword);inline;static;
214211 var
215212 i:integer;
216213 begin
217214 z:=i1; w:=i2; jsr:=i3; jcong:=i4; a:=i5; b:=i6;
218215 { Example procedure to set the table using KISS:}
219216 for i:=0 to 255 do t[i]:=KISS;
220217 end;
221218
222219 class function TMarsagliaPrngs.MWC:dword;inline;static;
223220 begin
224221 Result:= (znew << 16)+wnew;
225222 end;
226223
227224 class function TMarsagliaPrngs.SHR3:dword;inline;static;
228225 begin
229226 jsr:=jsr xor(jsr << 17); jsr:= jsr xor(jsr >> 13); jsr:=jsr xor(jsr << 5);
230227 result := jsr;
231228 end;
232229
233230 class function TMarsagliaPrngs.CONG:dword;inline;static;
234231 begin
235232 jcong:=69069*jcong+1234567;
236233 Result := jcong;
237234 end;
238235
239236 class function TMarsagliaPrngs.FIB:dword;inline;static;
240237 begin
241238 b:=a+b;a:=b-a;
242239 Result := a;
243240 end;
244241
245242 class function TMarsagliaPrngs.KISS:dword;inline;static;
246243 begin
247244 Result:= (MWC xor CONG)+SHR3;
248245 end;
249246
250247 class function TMarsagliaPrngs.LFIB4:dword;inline;static;
251248 begin
252249 inc(c);
253250 t[c]:=t[c]+t[(c+58) and 255]+t[(c+119) and 255]+t[(c+178) and 255];
254251 Result:=t[c];
255252 end;
256253
257254 class function TMarsagliaPrngs.SWB:dword;inline;static;
258255 begin
259256 inc(c);bro:=ord(x<y);
260257 x:=t[(c+34) and 255];
261258 y:=t[(c+19) and 255]+bro;
262259 t[c] := x-y;
263260 Result:= t[c];
264261 end;
265262
266263 class function TMarsagliaPrngs.XOS:dword;inline;static;
267264 var tmp:dword;
268265 begin
269266 tmp:=(x xor (x<<15));
270267 x:=y;
271268 y:=z;
272269 z:=w;
273270 w:=(w xor (w>>21)) xor (tmp xor(tmp>>4));
274271 Result := w;
275272 end;
276273
277274 class procedure TMarsagliaPrngs.Randomize;inline;static;
278275 begin
279276 {$WARNING This is not implemented here yet, so use system.random}
280277 system.randomize;
281278 for i:=0 to 255 do t[i]:=system.random(256);
282279 end;
283280
284281 function ScaleToFloat(const value:dword; Signed:Boolean=true):single;inline;
285282 begin
286283 case Signed of
287284 False:Result:= dword(value) * 2.328306e-10;
288285 True :Result:= longint(value) * 4.656613e-10;
289286 end;
290287 end;
291288
292289 end.
293290```
294291
295292### Example
296293
297294The original C code contained an example, here translated to Object Pascal. It is just a proof that we get the same results as intended.
298295
299296``` pascal
300297{$mode objfpc}{$I-}
301298{ It is basically Marsaglia's C test program in Pascal }
302299uses
303300 uMarsaglia;
304301var
305302 i:integer;
306303 k:dword;
307304begin
308305 // Set the table to known values, so we can verify the results.
309306 // The one million iterations per prng are not a mistake.
310307 // The whole program will finish in less than .5 seconds even on a Raspberry pi one.
311308 // Order is important: some seeds are taken from other prng's
312309 Prng.settable(12345,65435,34221,12345,9983651,95746118);
313310 for i:=1 to 1000000 do k:=Prng.LFIB4;writeln('LFIB4 ','Pass: ',k-1064612766=0);
314311 for i:=1 to 1000000 do k:=Prng.SWB; writeln('SWB ','Pass: ',k- 627749721=0);
315312 for i:=1 to 1000000 do k:=Prng.KISS; writeln('KISS ','Pass: ',k-1372460312=0);
316313 for i:=1 to 1000000 do k:=Prng.CONG; writeln('CONG ','Pass: ',k-1529210297=0);
317314 for i:=1 to 1000000 do k:=Prng.SHR3; writeln('SHR3 ','Pass: ',k-2642725982=0);
318315 for i:=1 to 1000000 do k:=Prng.MWC; writeln('MWC ','Pass: ',k- 904977562=0);
319316 for i:=1 to 1000000 do k:=Prng.FIB; writeln('FIB ','Pass: ',k-3519793928=0);
320317 for i:=1 to 1000000 do k:=Prng.XOS; writeln('XOS ','Pass: ',k-1110212780=0);
321318 // Scale to float demo
322319 for i := 0 to 9 do writeln(ScaleToFloat(Prng.SHR3):2:10);
323320 writeln('..........................');
324321 for i := 0 to 9 do writeln(ScaleToFloat(Prng.SHR3, false):2:10);
325322end.
326323```
327324
328325### Tests
329326
330327The above routines are tested with FIPS-140-2 and 1000 series, which is just ***indicative***. A full Dieharder test for any of them can be found on the web.
331328
332329Note there can always be a "failure" since statistics predict that a failure can always happen by chance. Any of the algorithms with few failures is usable. Particulary the fast KISS+SWB that passes Dieharder and XOS that is blazing fast and as good as FPC's Mersenne twister. ote you can also test against Crush/BigCrush, but that test suite is not suitable for 32 bit Prng's as per their documentation.
333330
334-<figure>
335-<img src="Selection_018.png" title="Selection_018.png" />
336-<figcaption>Selection_018.png</figcaption>
337-</figure>
331+![](/wiki-images/5/52/Selection_018.png)
338332
339333### Can we have one of these as the standard random, plz?
340334
341335**No you can't.**
342336
343337Programming languages tend not to change their PRNG and Free Pascal has a good one. It is important for a programming language to have a predictable PRNG. Many software relies on that. It would break backwards compatibility if the PRNG in a programming language would change. This is not a minor, but a very major issue. E.g. many existing datasets would become untestible and unverifiable. Even if some of the prng's that are presented here are superior in speed and properties, because of the above I hope the default Random will never be replaced. And you should hope so too..
344338
345339But if you need higher speed or better properties, just use one or a combination of these...
346340
347341### References
348342
3493431. [The original post by George Marsaglia](http://www.ciphersbyritter.com/NEWS4/RANDC.HTM#369B5E30.65A55FD1@stat.fsu.edu)\
3503442. [George Marsaglia, XorShift RNG's, Journal of Statistical Software volume 8 issue 14, July 2003](http://www.jstatsoft.org/v08/i14/paper)
3513453. [Diehard tests](https://en.wikipedia.org/wiki/Diehard_tests)
3523464. [Dieharder tests homepage, diegarder available for most linux distro's](http://www.phy.duke.edu/~rgb/General/dieharder.php)
3533475. [FIPS-140-2](https://en.wikipedia.org/wiki/FIPS_140-2)
3543486. [rngtest 2, available for most linux distro's](https://wiki.archlinux.org/index.php/Rng-tools)
355349
356350## See also
357351
358352- [[Dev random]]
359353- [[Functions for descriptive statistics]]
360354- [[Generating Random Numbers]]
361355
362356### TODO
363357
364358Provide X-platform randomize (other than FPC's random) based on timer, Windows RtlGenRandom and Unix /dev/random, /dev/urandom to seed the prng's
365359
366360---
367361*From the Free Pascal wiki, page "Marsaglia's pseudo random number generators", as it stood on 2024-03-03 after a change by Thaddy, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
368362Category: Code
369363Category: Mathematics
370364Category: Modelling and Simulation
371365Category: Statistical algorithms

Back to history