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