1 /******************************************************************************* 2 3 Copyright: 4 Copyright (c) 2008. Fawzi Mohamed 5 Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH. 6 All rights reserved. 7 8 License: 9 Tango Dual License: 3-Clause BSD License / Academic Free License v3.0. 10 See LICENSE_TANGO.txt for details. 11 12 Version: Initial release: July 2008 13 14 Authors: Fawzi Mohamed 15 16 *******************************************************************************/ 17 module ocean.math.random.engines.KISS; 18 import ocean.transition; 19 import Integer = ocean.text.convert.Integer_tango; 20 import ocean.core.Verify; 21 22 /+ Kiss99 random number generator, by Marisaglia 23 + a simple RNG that passes all statistical tests 24 + This is the engine, *never* use it directly, always use it though a RandomG class 25 +/ 26 struct Kiss99{ 27 private uint kiss_x = 123456789; 28 private uint kiss_y = 362436000; 29 private uint kiss_z = 521288629; 30 private uint kiss_c = 7654321; 31 private uint nBytes = 0; 32 private uint restB = 0; 33 34 enum int canCheckpoint=true; 35 enum int canSeed=true; 36 37 void skip(uint n){ 38 for (int i=n;i!=n;--i){ 39 next; 40 } 41 } 42 ubyte nextB(){ 43 if (nBytes>0) { 44 ubyte res=cast(ubyte)(restB & 0xFF); 45 restB >>= 8; 46 --nBytes; 47 return res; 48 } else { 49 restB=next; 50 ubyte res=cast(ubyte)(restB & 0xFF); 51 restB >>= 8; 52 nBytes=3; 53 return res; 54 } 55 } 56 uint next(){ 57 enum ulong a = 698769069UL; 58 ulong t; 59 kiss_x = 69069*kiss_x+12345; 60 kiss_y ^= (kiss_y<<13); kiss_y ^= (kiss_y>>17); kiss_y ^= (kiss_y<<5); 61 t = a*kiss_z+kiss_c; kiss_c = cast(uint)(t>>32); 62 kiss_z=cast(uint)t; 63 return kiss_x+kiss_y+kiss_z; 64 } 65 ulong nextL(){ 66 return ((cast(ulong)next)<<32)+cast(ulong)next; 67 } 68 69 void seed(scope uint delegate() r){ 70 kiss_x = r(); 71 for (int i=0;i<100;++i){ 72 kiss_y=r(); 73 if (kiss_y!=0) break; 74 } 75 if (kiss_y==0) kiss_y=362436000; 76 kiss_z=r(); 77 /* Don’t really need to seed c as well (is reset after a next), 78 but doing it allows to completely restore a given internal state */ 79 kiss_c = r() % 698769069; /* Should be less than 698769069 */ 80 nBytes = 0; 81 restB=0; 82 } 83 /// writes the current status in a string 84 istring toString(){ 85 char[] res=new char[6+6*9]; 86 int i=0; 87 res[i..i+6]="KISS99"; 88 i+=6; 89 foreach (val;[kiss_x,kiss_y,kiss_z,kiss_c,nBytes,restB]){ 90 res[i]='_'; 91 ++i; 92 Integer.format(res[i..i+8],val,"x8"); 93 i+=8; 94 } 95 verify(i==res.length,"unexpected size"); 96 return assumeUnique(res); 97 } 98 /// reads the current status from a string (that should have been trimmed) 99 /// returns the number of chars read 100 size_t fromString(cstring s){ 101 size_t i=0; 102 verify(s[i..i+4]=="KISS","unexpected kind, expected KISS"); 103 verify(s[i+4..i+7]=="99_","unexpected version, expected 99"); 104 i+=6; 105 foreach (val;[&kiss_x,&kiss_y,&kiss_z,&kiss_c,&nBytes,&restB]){ 106 verify(s[i]=='_',"no separator _ found"); 107 ++i; 108 uint ate; 109 *val=cast(uint)Integer.convert(s[i..i+8],16,&ate); 110 verify(ate==8,"unexpected read size"); 111 i+=8; 112 } 113 return i; 114 } 115 }