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 }