1 /******************************************************************************* 2 copyright: Copyright (c) 2008. Fawzi Mohamed 3 license: BSD style: $(LICENSE) 4 version: Initial release: July 2008 5 author: Fawzi Mohamed 6 *******************************************************************************/ 7 module tango.math.random.engines.CMWC; 8 private import Integer=tango.text.convert.Integer; 9 10 /+ CMWC a random number generator, 11 + Marisaglia, Journal of Modern Applied Statistical Methods (2003), vol.2,No.1,p 2-13 12 + a simple and fast RNG that passes all statistical tests, has a large seed, and is very fast 13 + By default ComplimentaryMultiplyWithCarry with r=1024, a=987769338, b=2^32-1, period a*b^r>10^9873 14 + This is the engine, *never* use it directly, always use it though a RandomG class 15 +/ 16 struct CMWC(uint cmwc_r=1024U,ulong cmwc_a=987769338UL){ 17 uint[cmwc_r] cmwc_q=void; 18 uint cmwc_i=cmwc_r-1u; 19 uint cmwc_c=123; 20 uint nBytes = 0; 21 uint restB = 0; 22 23 enum int canCheckpoint=true; 24 enum int canSeed=true; 25 26 void skip(uint n){ 27 for (int i=n;i!=n;--i){ 28 next(); 29 } 30 } 31 ubyte nextB(){ 32 if (nBytes>0) { 33 ubyte res=cast(ubyte)(restB & 0xFF); 34 restB >>= 8; 35 --nBytes; 36 return res; 37 } else { 38 restB=next(); 39 ubyte res=cast(ubyte)(restB & 0xFF); 40 restB >>= 8; 41 nBytes=3; 42 return res; 43 } 44 } 45 uint next(){ 46 enum uint rMask=cmwc_r-1u; 47 static assert((rMask&cmwc_r)==0,"cmwc_r is supposed to be a power of 2"); // put a more stringent test? 48 enum uint m=0xFFFF_FFFE; 49 cmwc_i=(cmwc_i+1)&rMask; 50 ulong t=cmwc_a*cmwc_q[cmwc_i]+cmwc_c; 51 cmwc_c=cast(uint)(t>>32); 52 uint x=cast(uint)t+cmwc_c; 53 if (x<cmwc_c) { 54 ++x; ++cmwc_c; 55 } 56 return (cmwc_q[cmwc_i]=m-x); 57 } 58 59 ulong nextL(){ 60 return ((cast(ulong)next())<<32)+cast(ulong)next(); 61 } 62 63 void seed(scope uint delegate() rSeed){ 64 cmwc_i=cmwc_r-1u; // randomize also this? 65 for (int ii=0;ii<10;++ii){ 66 for (uint i=0;i<cmwc_r;++i){ 67 cmwc_q[i]=rSeed(); 68 } 69 uint nV=rSeed(); 70 uint to=(uint.max/cmwc_a)*cmwc_a; 71 for (int i=0;i<10;++i){ 72 if (nV<to) break; 73 nV=rSeed(); 74 } 75 cmwc_c=cast(uint)(nV%cmwc_a); 76 nBytes = 0; 77 restB=0; 78 if (cmwc_c==0){ 79 for (uint i=0;i<cmwc_r;++i) 80 if (cmwc_q[i]!=0) return; 81 } else if (cmwc_c==cmwc_a-1){ 82 for (uint i=0;i<cmwc_r;++i) 83 if (cmwc_q[i]!=0xFFFF_FFFF) return; 84 } else return; 85 } 86 cmwc_c=1; 87 } 88 /// writes the current status in a string 89 immutable(char)[] toString(){ 90 char[] res=new char[4+16+(cmwc_r+5)*9]; 91 int i=0; 92 res[i..i+4]="CMWC"[]; 93 i+=4; 94 Integer.format(res[i..i+16],cmwc_a,cast(char[])"x16"); 95 i+=16; 96 res[i]='_'; 97 ++i; 98 Integer.format(res[i..i+8],cmwc_r,cast(char[])"x8"); 99 i+=8; 100 foreach (val;cmwc_q){ 101 res[i]='_'; 102 ++i; 103 Integer.format(res[i..i+8],val,cast(char[])"x8"); 104 i+=8; 105 } 106 foreach (val;[cmwc_i,cmwc_c,nBytes,restB]){ 107 res[i]='_'; 108 ++i; 109 Integer.format(res[i..i+8],val,cast(char[])"x8"); 110 i+=8; 111 } 112 assert(i==res.length,"unexpected size"); 113 return cast(immutable(char)[])res; 114 } 115 /// reads the current status from a string (that should have been trimmed) 116 /// returns the number of chars read 117 size_t fromString(const(char[]) s){ 118 char[16] tmpC; 119 size_t i=0; 120 assert(s[i..i+4]=="CMWC","unexpected kind, expected CMWC"); 121 i+=4; 122 assert(s[i..i+16]==Integer.format(tmpC,cmwc_a,"x16"),"unexpected cmwc_a"); 123 i+=16; 124 assert(s[i]=='_',"unexpected format, expected _"); 125 i++; 126 assert(s[i..i+8]==Integer.format(tmpC,cmwc_r,"x8"),"unexpected cmwc_r"); 127 i+=8; 128 foreach (ref val;cmwc_q){ 129 assert(s[i]=='_',"no separator _ found"); 130 ++i; 131 size_t ate; 132 val=cast(uint)Integer.convert(s[i..i+8],16,&ate); 133 assert(ate==8,"unexpected read size"); 134 i+=8; 135 } 136 foreach (val;[&cmwc_i,&cmwc_c,&nBytes,&restB]){ 137 assert(s[i]=='_',"no separator _ found"); 138 ++i; 139 size_t ate; 140 *val=cast(uint)Integer.convert(s[i..i+8],16,&ate); 141 assert(ate==8,"unexpected read size"); 142 i+=8; 143 } 144 return i; 145 } 146 } 147 148 /// some variations, the first has a period of ~10^39461, the first number (r) is basically the size of the seed 149 /// (and all bit patterns of that size are guarenteed to crop up in the period), the period is 2^(32*r)*a 150 alias CMWC!(4096U,18782UL) CMWC_4096_1; 151 alias CMWC!(2048U,1030770UL) CMWC_2048_1; 152 alias CMWC!(2048U,1047570UL) CMWC_2048_2; 153 alias CMWC!(1024U,5555698UL) CMWC_1024_1; 154 alias CMWC!(1024U,987769338UL) CMWC_1024_2; 155 alias CMWC!(512U,123462658UL) CMWC_512_1; 156 alias CMWC!(512U,123484214UL) CMWC_512_2; 157 alias CMWC!(256U,987662290UL) CMWC_256_1; 158 alias CMWC!(256U,987665442UL) CMWC_256_2; 159 alias CMWC!(128U,987688302UL) CMWC_128_1; 160 alias CMWC!(128U,987689614UL) CMWC_128_2; 161 alias CMWC!(64U ,987651206UL) CMWC_64_1; 162 alias CMWC!(64U ,987657110UL) CMWC_64_2; 163 alias CMWC!(32U ,987655670UL) CMWC_32_1; 164 alias CMWC!(32U ,987655878UL) CMWC_32_2; 165 alias CMWC!(16U ,987651178UL) CMWC_16_1; 166 alias CMWC!(16U ,987651182UL) CMWC_16_2; 167 alias CMWC!(8U ,987651386UL) CMWC_8_1; 168 alias CMWC!(8U ,987651670UL) CMWC_8_2; 169 alias CMWC!(4U ,987654366UL) CMWC_4_1; 170 alias CMWC!(4U ,987654978UL) CMWC_4_2; 171 alias CMWC_1024_2 CMWC_default;