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.KissCmwc; 8 private import Integer = tango.text.convert.Integer; 9 10 /+ CMWC and KISS random number generators combined, for extra security wrt. plain CMWC and 11 + Marisaglia, Journal of Modern Applied Statistical Methods (2003), vol.2,No.1,p 2-13 12 + a simple safe and fast RNG that passes all statistical tests, has a large seed, and is reasonably fast 13 + This is the engine, *never* use it directly, always use it though a RandomG class 14 +/ 15 struct KissCmwc(uint cmwc_r=1024U,ulong cmwc_a=987769338UL){ 16 uint[cmwc_r] cmwc_q=void; 17 uint cmwc_i=cmwc_r-1u; 18 uint cmwc_c=123; 19 private uint kiss_x = 123456789; 20 private uint kiss_y = 362436000; 21 private uint kiss_z = 521288629; 22 private uint kiss_c = 7654321; 23 uint nBytes = 0; 24 uint restB = 0; 25 26 enum int canCheckpoint=true; 27 enum int canSeed=true; 28 29 void skip(uint n){ 30 for (int i=n;i!=n;--i){ 31 next(); 32 } 33 } 34 ubyte nextB(){ 35 if (nBytes>0) { 36 ubyte res=cast(ubyte)(restB & 0xFF); 37 restB >>= 8; 38 --nBytes; 39 return res; 40 } else { 41 restB=next(); 42 ubyte res=cast(ubyte)(restB & 0xFF); 43 restB >>= 8; 44 nBytes=3; 45 return res; 46 } 47 } 48 uint next(){ 49 enum uint rMask=cmwc_r-1u; 50 static assert((rMask&cmwc_r)==0,"cmwc_r is supposed to be a power of 2"); // put a more stringent test? 51 enum uint m=0xFFFF_FFFE; 52 cmwc_i=(cmwc_i+1)&rMask; 53 ulong t=cmwc_a*cmwc_q[cmwc_i]+cmwc_c; 54 cmwc_c=cast(uint)(t>>32); 55 uint x=cast(uint)t+cmwc_c; 56 if (x<cmwc_c) { 57 ++x; ++cmwc_c; 58 } 59 enum ulong a = 698769069UL; 60 ulong k_t; 61 kiss_x = 69069*kiss_x+12345; 62 kiss_y ^= (kiss_y<<13); kiss_y ^= (kiss_y>>17); kiss_y ^= (kiss_y<<5); 63 k_t = a*kiss_z+kiss_c; kiss_c = cast(uint)(k_t>>32); 64 kiss_z=cast(uint)k_t; 65 return (cmwc_q[cmwc_i]=m-x)+kiss_x+kiss_y+kiss_z; // xor to avoid overflow? 66 } 67 68 ulong nextL(){ 69 return ((cast(ulong)next())<<32)+cast(ulong)next(); 70 } 71 72 void seed(scope uint delegate() rSeed){ 73 kiss_x = rSeed(); 74 for (int i=0;i<100;++i){ 75 kiss_y=rSeed(); 76 if (kiss_y!=0) break; 77 } 78 if (kiss_y==0) kiss_y=362436000; 79 kiss_z=rSeed(); 80 /* Don’t really need to seed c as well (is reset after a next), 81 but doing it allows to completely restore a given internal state */ 82 kiss_c = rSeed() % 698769069; /* Should be less than 698769069 */ 83 84 cmwc_i=cmwc_r-1u; // randomize also this? 85 for (int ii=0;ii<10;++ii){ 86 for (uint i=0;i<cmwc_r;++i){ 87 cmwc_q[i]=rSeed(); 88 } 89 uint nV=rSeed(); 90 uint to=(uint.max/cmwc_a)*cmwc_a; 91 for (int i=0;i<10;++i){ 92 if (nV<to) break; 93 nV=rSeed(); 94 } 95 cmwc_c=cast(uint)(nV%cmwc_a); 96 nBytes = 0; 97 restB=0; 98 if (cmwc_c==0){ 99 for (uint i=0;i<cmwc_r;++i) 100 if (cmwc_q[i]!=0) return; 101 } else if (cmwc_c==cmwc_a-1){ 102 for (uint i=0;i<cmwc_r;++i) 103 if (cmwc_q[i]!=0xFFFF_FFFF) return; 104 } else return; 105 } 106 cmwc_c=1; 107 } 108 /// writes the current status in a string 109 immutable(char)[] toString(){ 110 char[] res=new char[11+16+(cmwc_r+9)*9]; 111 int i=0; 112 res[i..i+11]="CMWC+KISS99"[]; 113 i+=11; 114 Integer.format(res[i..i+16],cmwc_a,cast(char[])"x16"); 115 i+=16; 116 res[i]='_'; 117 ++i; 118 Integer.format(res[i..i+8],cmwc_r,cast(char[])"x8"); 119 i+=8; 120 foreach (val;cmwc_q){ 121 res[i]='_'; 122 ++i; 123 Integer.format(res[i..i+8],val,cast(char[])"x8"); 124 i+=8; 125 } 126 foreach (val;[cmwc_i,cmwc_c,nBytes,restB,kiss_x,kiss_y,kiss_z,kiss_c]){ 127 res[i]='_'; 128 ++i; 129 Integer.format(res[i..i+8],val,cast(char[])"x8"); 130 i+=8; 131 } 132 assert(i==res.length,"unexpected size"); 133 return cast(immutable(char)[])res; 134 } 135 /// reads the current status from a string (that should have been trimmed) 136 /// returns the number of chars read 137 size_t fromString(const(char[]) s){ 138 char[16] tmpC; 139 size_t i=0; 140 assert(s[i..i+11]=="CMWC+KISS99","unexpected kind, expected CMWC+KISS99"); 141 i+=11; 142 assert(s[i..i+16]==Integer.format(tmpC,cmwc_a,"x16"),"unexpected cmwc_a"); 143 i+=16; 144 assert(s[i]=='_',"unexpected format, expected _"); 145 i++; 146 assert(s[i..i+8]==Integer.format(tmpC,cmwc_r,"x8"),"unexpected cmwc_r"); 147 i+=8; 148 foreach (ref val;cmwc_q){ 149 assert(s[i]=='_',"no separator _ found"); 150 ++i; 151 size_t ate; 152 val=cast(uint)Integer.convert(s[i..i+8],16,&ate); 153 assert(ate==8,"unexpected read size"); 154 i+=8; 155 } 156 foreach (val;[&cmwc_i,&cmwc_c,&nBytes,&restB,&kiss_x,&kiss_y,&kiss_z,&kiss_c]){ 157 assert(s[i]=='_',"no separator _ found"); 158 ++i; 159 size_t ate; 160 *val=cast(uint)Integer.convert(s[i..i+8],16,&ate); 161 assert(ate==8,"unexpected read size"); 162 i+=8; 163 } 164 return i; 165 } 166 } 167 168 /// some variations of the CMWC part, the first has a period of ~10^39461 169 /// the first number (r) is basically the size of the seed and storage (and all bit patterns 170 /// of that size are guarenteed to crop up in the period), the period is (2^32-1)^r*a 171 alias KissCmwc!(4096U,18782UL) KissCmwc_4096_1; 172 alias KissCmwc!(2048U,1030770UL) KissCmwc_2048_1; 173 alias KissCmwc!(2048U,1047570UL) KissCmwc_2048_2; 174 alias KissCmwc!(1024U,5555698UL) KissCmwc_1024_1; 175 alias KissCmwc!(1024U,987769338UL) KissCmwc_1024_2; 176 alias KissCmwc!(512U,123462658UL) KissCmwc_512_1; 177 alias KissCmwc!(512U,123484214UL) KissCmwc_512_2; 178 alias KissCmwc!(256U,987662290UL) KissCmwc_256_1; 179 alias KissCmwc!(256U,987665442UL) KissCmwc_256_2; 180 alias KissCmwc!(128U,987688302UL) KissCmwc_128_1; 181 alias KissCmwc!(128U,987689614UL) KissCmwc_128_2; 182 alias KissCmwc!(64U ,987651206UL) KissCmwc_64_1; 183 alias KissCmwc!(64U ,987657110UL) KissCmwc_64_2; 184 alias KissCmwc!(32U ,987655670UL) KissCmwc_32_1; 185 alias KissCmwc!(32U ,987655878UL) KissCmwc_32_2; 186 alias KissCmwc!(16U ,987651178UL) KissCmwc_16_1; 187 alias KissCmwc!(16U ,987651182UL) KissCmwc_16_2; 188 alias KissCmwc!(8U ,987651386UL) KissCmwc_8_1; 189 alias KissCmwc!(8U ,987651670UL) KissCmwc_8_2; 190 alias KissCmwc!(4U ,987654366UL) KissCmwc_4_1; 191 alias KissCmwc!(4U ,987654978UL) KissCmwc_4_2; 192 alias KissCmwc_1024_2 KissCmwc_default;