# Marsaglia random numbers

In 1999, George Marsaglia posted a number of random-number generator on several mailing lists. They are defined as C macros, and use eleven global variables, of which eight are just a single letter. I have made them ito a C++ class containing inline functions. Here is the long but narrow header file:

```# pragma once

class Marsaglia {
public:
typedef int            int32;
typedef unsigned      uint32;
typedef unsigned char uchar;

inline uint32 shr3() {   //--- Period 2^32
jsr  ^= (jsr << 17);
jsr  ^= (jsr >> 13);
jsr  ^= (jsr <<  5);
return jsr;
}

inline uint32 mwc() {    //--- Period 2^60
return (_znew()<<16) + _wnew();
}

inline uint32 kiss() {   //--- Period 2^123
return (mwc()^cong()) + shr3();
}

inline uint32 lfib4() {  //--- Period 2^287
c++;
table[c] += table[uc(c+ 58)];
table[c] += table[uc(c+119)];
table[c] += table[uc(c+178)];
return table[c];
}

inline uint32 swb() {    //--- Period 2^7578
c++;
bro      = (x<y);
y        = table[uc(c+19)]+bro;
x        = table[uc(c+34)];
table[c] = x-y;
return table[c];
}

inline double uni() {
return (kiss()*2.328306e-10);
}

inline double vni() {
return ((int32)kiss())*4.656613e-10;
}

void settable(); //--- Uses rand() for seeding

void settable(uint32 z,     uint32 w, uint32 jsr,
uint32 jcong, uint32 a, uint32 b);

void set_xybroc(uint32 x = 0,  uint32  y = 0,
uint32 bro = 0, uint32 c = 0);

public:
//--- cong() and fib() should probably not be used
//--- directly, so should be private.  However, the test
//--- program marsaglia-main.cc uses them.  Read
//--- Marsaglia's comments, below, before using them
//--- directly
inline uint32 cong() {
return (jcong = 69069*jcong+1234567);
}

inline uint32 fib() {
return ((b = a+b),(a = b-a));
}

private:
inline uchar uc(uint32 v) { return v; } //--- Implicit cast

inline uint32 _znew() {
z = 36969 * (z & 65535) + (z >> 16);
return z;
}

inline uint32 _wnew() {
w = 18000 * (w & 65535) + (w >> 16);
return w;
}

private:
uint32 z     = 362436069;  // _znew,  mwc -> kiss
uint32 w     = 521288629;  // _wnew,  mwc -> kiss
uint32 jsr   = 123456789;  //        shr3 -> kiss
uint32 jcong = 380116160;  //        cong -> kiss
uint32 a     = 224466889;  // fib
uint32 b     =   7584631;  // fib

// !!! Warning: table[] is not initialized; see settable()
uint32 table;     // swb, lfib4
uint32 x     = 0;  // swb
uint32 y     = 0;  // swb
uint32 bro   = 0;  // swb
uchar  c     = 0;  // swb, lfib4
};```

The interesting part is the first five random-number generators.

 shr3 Three shifts, with a period of 2^32-1. mwc Multiply With Carry, with a period of about 2^60. kiss Keep It Simple Stupid, with a period of about 2^123 lfib4 Lagged Fibonacci, with a period of about 2^287 swb Subtract with borrow. Has a very long period: about 2^7578.

The remaining generators are not recommended for direct use, but are used by the five generators above.

How about execution times? Each generators has been tested by running it 10^9 times. This has been repeatd ten times, and the result sorted. The two sortest and the two longest times have been dropped, and the remaining six values have been averaged.

Each generator has been instantiated in four different ways

 As a static object An instance of class Marsaglia declared as a file-static variable. As an extern object An instance of class Marsaglia defined in another compilation unit. As a stack object An instance of class Marsaglia defined local to a function. As a namespace Using a rewrite of class Marsaglia as a namespace. This, of course, is not an object at all. The generators are ordered by increasing period. The tag M: in the plot identifies Marsaglia RNGs. In the next plot, there will be some other RNGs as well

Time was measured using the C++ library in std::chrono. The details are in the

As can be seen from the table, it really does not matter how the class is instantiated. Variations are withing the margin of error, and another compiler may give different results. The tests were compiled with GCC 9.1.0 with option -O3.

The times in this plot are relative, not absolute. On my Intel box running at 2.4 MHz, the fastest generator takes about 3 nanoseconds per iteration.
{"ft_lang_label":"__label__en","ft_lang_prob":0.7333071,"math_prob":0.9565709,"size":5032,"snap":"2023-14-2023-23","text_gpt3_token_len":1490,"char_repetition_ratio":0.13941926,"word_repetition_ratio":0.015681544,"special_character_ratio":0.33505565,"punctuation_ratio":0.16295546,"nsfw_num_words":0,"has_unicode_error":false,"math_prob_llama3":0.9888897,"pos_list":[0,1,2],"im_url_duplicate_count":[null,2,null],"WARC_HEADER":"{\"WARC-Type\":\"response\",\"WARC-Date\":\"2023-05-29T18:17:45Z\",\"WARC-Record-ID\":\"<urn:uuid:f91da35b-7b1c-4b74-bcfd-b78808c0508b>\",\"Content-Length\":\"30827\",\"Content-Type\":\"application/http; msgtype=response\",\"WARC-Warcinfo-ID\":\"<urn:uuid:6542c342-2af6-442d-88cc-9aaf131fdfbe>\",\"WARC-Concurrent-To\":\"<urn:uuid:9906328f-fce0-4b91-b798-04d377c51215>\",\"WARC-IP-Address\":\"2.248.198.58\",\"WARC-Target-URI\":\"https://www.sdu.se/blog/marsaglia-random-numbers/\",\"WARC-Payload-Digest\":\"sha1:3JPNCD3Y4NQCVCXCBGACPTOEVJOGBJL3\",\"WARC-Block-Digest\":\"sha1:W5ERZBRDHRMSPHQKXKC5VZ2HP76FBZ5V\",\"WARC-Identified-Payload-Type\":\"text/html\",\"warc_filename\":\"/cc_download/warc_2023/CC-MAIN-2023-23/CC-MAIN-2023-23_segments_1685224644907.31_warc_CC-MAIN-20230529173312-20230529203312-00042.warc.gz\"}"}