| 1 |
/******************************************************************************* |
|---|
| 2 |
Random number generators |
|---|
| 3 |
|
|---|
| 4 |
This is an attempt at having a good flexible and easy to use random number |
|---|
| 5 |
generator. |
|---|
| 6 |
ease of use: |
|---|
| 7 |
- shared generator for quick usage available through the "rand" object |
|---|
| 8 |
int i=rand.uniformR(10); // a random number from [0;10) |
|---|
| 9 |
- simple Random (non threadsafe) and RandomSync (threadsafe) types to |
|---|
| 10 |
create new generators (for heavy use a good idea is one Random object per thread) |
|---|
| 11 |
- several distributions can be requested like this |
|---|
| 12 |
rand.distributionD!(type)(paramForDistribution) |
|---|
| 13 |
the type can often be avoided if the parameters make it clear. |
|---|
| 14 |
From it single numbers can be generated with .getRandom(), and variables |
|---|
| 15 |
initialized either with call style (var) or with .randomize(var). |
|---|
| 16 |
Utility functions to generate numbers directly are also available. |
|---|
| 17 |
The choice to put all the distribution in a single object that caches them |
|---|
| 18 |
has made (for example) the gamma distribution very easy to implement. |
|---|
| 19 |
- sample usage: |
|---|
| 20 |
auto r=new Random(); |
|---|
| 21 |
int i; float f; real r; real[100] ar0; real[] ar=ar0[]; |
|---|
| 22 |
// initialize with uniform distribution |
|---|
| 23 |
r(i)(f)(r)(ar); |
|---|
| 24 |
// unfortunetely one cannot use directly ar0... |
|---|
| 25 |
// unifrom distribution 0..10 |
|---|
| 26 |
r.uniformR(10)(i)(f)(r)(ar); |
|---|
| 27 |
// uniform distribution -10..10 |
|---|
| 28 |
r.uniformRSymm(10)(i)(f)(r)(ar); |
|---|
| 29 |
// the distribution can be stored |
|---|
| 30 |
auto r2=r.uniformRSymm(10); |
|---|
| 31 |
// and used later |
|---|
| 32 |
r2(ar); |
|---|
| 33 |
// complex distributions (normal,exp,gamma) are produced for the requested type |
|---|
| 34 |
r.normalSource!(float)()(f); |
|---|
| 35 |
// with sigma=2 |
|---|
| 36 |
r.normalD(2.0f)(f); |
|---|
| 37 |
// and can be used also to initialize other types |
|---|
| 38 |
r.normalSource!(float)()(r)(ar); |
|---|
| 39 |
r.normalD(2.0f)(r)(ar); |
|---|
| 40 |
// but this is different from |
|---|
| 41 |
r.normalSource!(real)()(i)(r)(ar); |
|---|
| 42 |
r.normalD(2.0L)(i)(r)(ar); |
|---|
| 43 |
// as the source generates numbers of its type that then are simply casted to |
|---|
| 44 |
// the type needed. |
|---|
| 45 |
// Uniform distribution (as its creation for different types has no overhead) |
|---|
| 46 |
// never cast, so that (for example) bounds exclusion for floats is really |
|---|
| 47 |
// guaranteed. |
|---|
| 48 |
// For the other distribution using a distribution of different type than |
|---|
| 49 |
// the variable should be done with care, as underflow/overflow might ensue. |
|---|
| 50 |
// |
|---|
| 51 |
// some utility functions are also available |
|---|
| 52 |
int i2=r.uniform!(int)(); |
|---|
| 53 |
int i2=r.randomize(i); // both i and i2 are initialized to the same value |
|---|
| 54 |
float f2=r.normalSigma(3.0f); |
|---|
| 55 |
flexibility: |
|---|
| 56 |
- easily swappable basic source |
|---|
| 57 |
// a random generator that uses the system provided random generator: |
|---|
| 58 |
auto r=RandomG!(Urandom)(); |
|---|
| 59 |
- ziggurat generator can be easily adapted to any decreasing derivable |
|---|
| 60 |
distribution, the hard parametrization (to find xLast) can be done |
|---|
| 61 |
automatically |
|---|
| 62 |
- several distributions available "out of the box" |
|---|
| 63 |
quality: |
|---|
| 64 |
- the default Source (KISS99) passes all statistical tests |
|---|
| 65 |
(P. L'Ecuyer and R. Simard, ACM Transactions on Mathematical Software (2007), |
|---|
| 66 |
33, 4, Article 22) |
|---|
| 67 |
- floating point uniform generator always initializes the full mantissa, the |
|---|
| 68 |
only flaw is a (*very* small) predilection of 0 as least important bit |
|---|
| 69 |
(IEEE rounds to 0 in case of tie). |
|---|
| 70 |
Using a method that initializes the full mantissa was shown to improve the |
|---|
| 71 |
quality of subsequntly derived normal distribued numbers |
|---|
| 72 |
(Thomas et al. Gaussian random number generators. Acm Comput Surv (2007) |
|---|
| 73 |
vol. 39 (4) pp. 11)) |
|---|
| 74 |
- Ziggurat method, a very fast and accurate method was used for both Normal and |
|---|
| 75 |
exp distribued numbers. |
|---|
| 76 |
- gamma distribued numbers uses a method recently proposed by Marsaglia and |
|---|
| 77 |
Tsang. The method is very fast, and should be good. |
|---|
| 78 |
My (Fawzi's) feeling is that the transformation h(x)=(1+d*x)^3 might loose |
|---|
| 79 |
a couple of bits of precision in some cases, but it is unclear if this |
|---|
| 80 |
might become visible in (*very* extensive) tests or not. |
|---|
| 81 |
- the basic source can be easily be changed with something else |
|---|
| 82 |
efficiency: |
|---|
| 83 |
- very fast methods have been used, and some effort has been put into |
|---|
| 84 |
optimizing some of them, but not all, but the interface has been choosen |
|---|
| 85 |
so that close to optimal implementation can be provided through the same |
|---|
| 86 |
interface. |
|---|
| 87 |
- Normal and Exp sources allocated only upon request: no memory waste, but |
|---|
| 88 |
a (*very* small) speed hit, that can be avoided by storing the source in |
|---|
| 89 |
a variable and using it (not going through the RandomG) |
|---|
| 90 |
annoyances: |
|---|
| 91 |
- I have put quite some functionality in a single module, maybe some might |
|---|
| 92 |
prefer to split it up |
|---|
| 93 |
- I have added two "next" methods to RandomG for backward compatibility |
|---|
| 94 |
reasons, and replaced the .hared instance from Random has been |
|---|
| 95 |
replaced by the "rand" object. The idea behind this is that RandomG is |
|---|
| 96 |
a template and rand it should be shared across all templates. |
|---|
| 97 |
If the name rand is considered bad one could change it. |
|---|
| 98 |
I kept .shared static method that returns rand, so this remain a dropin |
|---|
| 99 |
replacement of the old random. |
|---|
| 100 |
- you cannot initialize a static array directly, this because randomize is |
|---|
| 101 |
declared like this: |
|---|
| 102 |
U randomize(U)(ref U a) { } |
|---|
| 103 |
and a static array cannot be passed by reference. Removing the ref would |
|---|
| 104 |
make arrays initialized, and scalar not, which is much worse. |
|---|
| 105 |
|
|---|
| 106 |
copyright: Copyright (c) 2008. Fawzi Mohamed |
|---|
| 107 |
license: BSD style: $(LICENSE) |
|---|
| 108 |
version: Initial release: July 2008 |
|---|
| 109 |
author: Fawzi Mohamed |
|---|
| 110 |
|
|---|
| 111 |
*******************************************************************************/ |
|---|
| 112 |
module tango.math.Random; |
|---|
| 113 |
import tango.io.protocol.model.IWriter:IWritable,IWriter; |
|---|
| 114 |
import tango.io.protocol.model.IReader:IReadable,IReader; |
|---|
| 115 |
import Integer = tango.text.convert.Integer; |
|---|
| 116 |
import tango.math.Bracket:findRoot; |
|---|
| 117 |
import tango.core.sync.Mutex: Mutex; |
|---|
| 118 |
import tango.io.FileConduit; // use stdc read/write? |
|---|
| 119 |
import tango.math.Math:exp,sqrt,log,PI,abs; |
|---|
| 120 |
//import tango.math.Probability: normalDistributionCompl; |
|---|
| 121 |
import tango.math.ErrorFunction:erfc; |
|---|
| 122 |
//import tango.stdc.stdio:printf; |
|---|
| 123 |
|
|---|
| 124 |
version (Win32) |
|---|
| 125 |
private extern(Windows) int QueryPerformanceCounter (ulong *); |
|---|
| 126 |
|
|---|
| 127 |
version (Posix) |
|---|
| 128 |
{ |
|---|
| 129 |
private import tango.stdc.posix.sys.time; |
|---|
| 130 |
} |
|---|
| 131 |
|
|---|
| 132 |
version(darwin) { version=has_urandom; } |
|---|
| 133 |
version(linux) { version=has_urandom; } |
|---|
| 134 |
|
|---|
| 135 |
/// compile time integer power |
|---|
| 136 |
private T powI(T)(T x,int p){ |
|---|
| 137 |
T xx=cast(T)1; |
|---|
| 138 |
if (p<0){ |
|---|
| 139 |
p=-p; |
|---|
| 140 |
x=1/x; |
|---|
| 141 |
} |
|---|
| 142 |
for (int i=0;i<p;++i) |
|---|
| 143 |
xx*=x; |
|---|
| 144 |
return xx; |
|---|
| 145 |
} |
|---|
| 146 |
|
|---|
| 147 |
/// if T is a float |
|---|
| 148 |
template isFloat(T){ |
|---|
| 149 |
static if(is(T==float)||is(T==double)||is(T==real)){ |
|---|
| 150 |
const bool isFloat=true; |
|---|
| 151 |
} else { |
|---|
| 152 |
const bool isFloat=false; |
|---|
| 153 |
} |
|---|
| 154 |
} |
|---|
| 155 |
|
|---|
| 156 |
/// Strips the []'s off of a type. |
|---|
| 157 |
template arrayBaseT(T) |
|---|
| 158 |
{ |
|---|
| 159 |
static if( is( T S : S[]) ) { |
|---|
| 160 |
alias arrayBaseT!(S) arrayBaseT; |
|---|
| 161 |
} |
|---|
| 162 |
else { |
|---|
| 163 |
alias T arrayBaseT; |
|---|
| 164 |
} |
|---|
| 165 |
} |
|---|
| 166 |
|
|---|
| 167 |
|
|---|
| 168 |
/// very simple array based source (use with care, some methods in non uniform distributions |
|---|
| 169 |
/// expect a random source with correct statistics, and could loop forever with such a source) |
|---|
| 170 |
struct ArraySource{ |
|---|
| 171 |
uint[] a; |
|---|
| 172 |
size_t i; |
|---|
| 173 |
static ArraySource opCall(uint[] a,size_t i=0) |
|---|
| 174 |
in { assert(a.length>0,"array needs at least one element"); } |
|---|
| 175 |
body { |
|---|
| 176 |
ArraySource res; |
|---|
| 177 |
res.a=a; |
|---|
| 178 |
res.i=i; |
|---|
| 179 |
return res; |
|---|
| 180 |
} |
|---|
| 181 |
uint next(){ |
|---|
| 182 |
assert(a.length>i,"error, array out of bounds"); |
|---|
| 183 |
uint el=a[i]; |
|---|
| 184 |
i=(i+1)%a.length; |
|---|
| 185 |
return el; |
|---|
| 186 |
} |
|---|
| 187 |
ubyte nextB(){ |
|---|
| 188 |
return cast(ubyte)(0xFF&next); |
|---|
| 189 |
} |
|---|
| 190 |
ulong nextL(){ |
|---|
| 191 |
return ((cast(ulong)next)<<32)+cast(ulong)next; |
|---|
| 192 |
} |
|---|
| 193 |
} |
|---|
| 194 |
|
|---|
| 195 |
version(has_urandom) { |
|---|
| 196 |
/// basic source that takes data from system random device |
|---|
| 197 |
/// This is an engine, do not use directly, use RandomG!(Urandom) |
|---|
| 198 |
/// should use stdc rad/write? |
|---|
| 199 |
struct URandom{ |
|---|
| 200 |
static FileConduit.Style readStyle; |
|---|
| 201 |
static Mutex lock; |
|---|
| 202 |
static this(){ |
|---|
| 203 |
readStyle.access=FileConduit.Access.Read; |
|---|
| 204 |
readStyle.open =FileConduit.Open.Exists; |
|---|
| 205 |
readStyle.share =FileConduit.Share.Read; |
|---|
| 206 |
readStyle.cache =FileConduit.Cache.None; |
|---|
| 207 |
|
|---|
| 208 |
lock=new Mutex(); |
|---|
| 209 |
} |
|---|
| 210 |
const int canCheckpoint=false; |
|---|
| 211 |
const int canSeed=false; |
|---|
| 212 |
|
|---|
| 213 |
void skip(uint n){ } |
|---|
| 214 |
ubyte nextB(){ |
|---|
| 215 |
union ToVoidA{ |
|---|
| 216 |
ubyte i; |
|---|
| 217 |
void[1] a; |
|---|
| 218 |
} |
|---|
| 219 |
ToVoidA el; |
|---|
| 220 |
synchronized(lock){ |
|---|
| 221 |
auto fn = new FileConduit("/dev/urandom", readStyle); |
|---|
| 222 |
if(fn.read(el.a)!=el.a.length){ |
|---|
| 223 |
throw new Exception("could not write the requested bytes from urandom"); |
|---|
| 224 |
} |
|---|
| 225 |
fn.close(); |
|---|
| 226 |
} |
|---|
| 227 |
return el.i; |
|---|
| 228 |
} |
|---|
| 229 |
uint next(){ |
|---|
| 230 |
union ToVoidA{ |
|---|
| 231 |
uint i; |
|---|
| 232 |
void[4] a; |
|---|
| 233 |
} |
|---|
| 234 |
ToVoidA el; |
|---|
| 235 |
synchronized(lock){ |
|---|
| 236 |
auto fn = new FileConduit("/dev/urandom", readStyle); |
|---|
| 237 |
if(fn.read(el.a)!=el.a.length){ |
|---|
| 238 |
throw new Exception("could not write the requested bytes from urandom"); |
|---|
| 239 |
} |
|---|
| 240 |
fn.close(); |
|---|
| 241 |
} |
|---|
| 242 |
return el.i; |
|---|
| 243 |
} |
|---|
| 244 |
ulong nextL(){ |
|---|
| 245 |
union ToVoidA{ |
|---|
| 246 |
ulong l; |
|---|
| 247 |
void[8] a; |
|---|
| 248 |
} |
|---|
| 249 |
ToVoidA el; |
|---|
| 250 |
synchronized(lock){ |
|---|
| 251 |
auto fn = new FileConduit("/dev/urandom", readStyle); |
|---|
| 252 |
if(fn.read(el.a)!=el.a.length){ |
|---|
| 253 |
throw new Exception("could not write the requested bytes from urandom"); |
|---|
| 254 |
} |
|---|
| 255 |
fn.close(); |
|---|
| 256 |
} |
|---|
| 257 |
return el.l; |
|---|
| 258 |
} |
|---|
| 259 |
|
|---|
| 260 |
void seed(uint delegate() r) { } |
|---|
| 261 |
/// IWritable implementation |
|---|
| 262 |
void write (IWriter input){ |
|---|
| 263 |
char[] r="URandom"; |
|---|
| 264 |
input(r); |
|---|
| 265 |
} |
|---|
| 266 |
/// IReadable implementation |
|---|
| 267 |
void read (IReader input){ |
|---|
| 268 |
char[] r; |
|---|
| 269 |
input(r); |
|---|
| 270 |
assert(r=="URandom","unexpected read"); |
|---|
| 271 |
} |
|---|
| 272 |
/// writes the current status in a string |
|---|
| 273 |
char[] toString(){ |
|---|
| 274 |
return "URandom"; |
|---|
| 275 |
} |
|---|
| 276 |
/// reads the current status from a string (that should have been trimmed) |
|---|
| 277 |
/// returns the number of chars read |
|---|
| 278 |
uint fromString(char[] s){ |
|---|
| 279 |
char[] r="URandom"; |
|---|
| 280 |
assert(s[0.. r.length]==r,"unxepected string instad of URandom:"~s); |
|---|
| 281 |
return r.length; |
|---|
| 282 |
} |
|---|
| 283 |
} |
|---|
| 284 |
} |
|---|
| 285 |
|
|---|
| 286 |
/+ Kiss99 random number generator, by Marisaglia |
|---|
| 287 |
+ a simple RNG that passes all statistical tests |
|---|
| 288 |
+ This is the engine, *never* use it directly, always use it though a RandomG class |
|---|
| 289 |
+/ |
|---|
| 290 |
struct Kiss99{ |
|---|
| 291 |
private uint kiss_x = 123456789; |
|---|
| 292 |
private uint kiss_y = 362436000; |
|---|
| 293 |
private uint kiss_z = 521288629; |
|---|
| 294 |
private uint kiss_c = 7654321; |
|---|
| 295 |
private uint nBytes = 0; |
|---|
| 296 |
private uint restB = 0; |
|---|
| 297 |
|
|---|
| 298 |
const int canCheckpoint=true; |
|---|
| 299 |
const int canSeed=true; |
|---|
| 300 |
|
|---|
| 301 |
void skip(uint n){ |
|---|
| 302 |
for (int i=n;i!=n;--i){ |
|---|
| 303 |
next; |
|---|
| 304 |
} |
|---|
| 305 |
} |
|---|
| 306 |
ubyte nextB(){ |
|---|
| 307 |
if (nBytes>0) { |
|---|
| 308 |
ubyte res=cast(ubyte)(restB & 0xFF); |
|---|
| 309 |
restB >>= 8; |
|---|
| 310 |
--nBytes; |
|---|
| 311 |
return res; |
|---|
| 312 |
} else { |
|---|
| 313 |
restB=next; |
|---|
| 314 |
ubyte res=cast(ubyte)(restB & 0xFF); |
|---|
| 315 |
restB >>= 8; |
|---|
| 316 |
nBytes=3; |
|---|
| 317 |
return res; |
|---|
| 318 |
} |
|---|
| 319 |
} |
|---|
| 320 |
uint next(){ |
|---|
| 321 |
const ulong a = 698769069UL; |
|---|
| 322 |
ulong t; |
|---|
| 323 |
kiss_x = 69069*kiss_x+12345; |
|---|
| 324 |
kiss_y ^= (kiss_y<<13); kiss_y ^= (kiss_y>>17); kiss_y ^= (kiss_y<<5); |
|---|
| 325 |
t = a*kiss_z+kiss_c; kiss_c = (t>>32); |
|---|
| 326 |
kiss_z=cast(uint)t; |
|---|
| 327 |
return kiss_x+kiss_y+kiss_z; |
|---|
| 328 |
} |
|---|
| 329 |
ulong nextL(){ |
|---|
| 330 |
return ((cast(ulong)next)<<32)+cast(ulong)next; |
|---|
| 331 |
} |
|---|
| 332 |
|
|---|
| 333 |
void seed(uint delegate() r){ |
|---|
| 334 |
kiss_x = r(); |
|---|
| 335 |
for (int i=0;i<100;++i){ |
|---|
| 336 |
kiss_y=r(); |
|---|
| 337 |
if (kiss_y!=0) break; |
|---|
| 338 |
} |
|---|
| 339 |
if (kiss_y==0) kiss_y=362436000; |
|---|
| 340 |
kiss_z=r(); |
|---|
| 341 |
/* Donât really need to seed c as well (is reset after a next), |
|---|
| 342 |
but doing it allows to completely restore a given internal state */ |
|---|
| 343 |
kiss_c = r() % 698769069; /* Should be less than 698769069 */ |
|---|
| 344 |
nBytes = 0; |
|---|
| 345 |
restB=0; |
|---|
| 346 |
} |
|---|
| 347 |
/// IWritable implementation |
|---|
| 348 |
void write (IWriter input){ |
|---|
| 349 |
input(kiss_x)(kiss_y)(kiss_z)(kiss_c)(nBytes)(restB); |
|---|
| 350 |
} |
|---|
| 351 |
/// IReadable implementation |
|---|
| 352 |
void read (IReader input){ |
|---|
| 353 |
input(kiss_x)(kiss_y)(kiss_z)(kiss_c)(nBytes)(restB); |
|---|
| 354 |
} |
|---|
| 355 |
/// writes the current status in a string |
|---|
| 356 |
char[] toString(){ |
|---|
| 357 |
char[] res=new char[6+6*9]; |
|---|
| 358 |
int i=0; |
|---|
| 359 |
res[i..i+6]="KISS99"; |
|---|
| 360 |
i+=6; |
|---|
| 361 |
foreach (val;[kiss_x,kiss_y,kiss_z,kiss_c,nBytes,restB]){ |
|---|
| 362 |
res[i]='_'; |
|---|
| 363 |
++i; |
|---|
| 364 |
Integer.format(res[i..i+8],val,"x8"); |
|---|
| 365 |
i+=8; |
|---|
| 366 |
} |
|---|
| 367 |
assert(i==res.length,"unexpected size"); |
|---|
| 368 |
return res; |
|---|
| 369 |
} |
|---|
| 370 |
/// reads the current status from a string (that should have been trimmed) |
|---|
| 371 |
/// returns the number of chars read |
|---|
| 372 |
uint fromString(char[] s){ |
|---|
| 373 |
uint i=0; |
|---|
| 374 |
assert(s[i..i+4]=="KISS","unexpected kind, expected KISS"); |
|---|
| 375 |
assert(s[i+4..i+7]=="99_","unexpected version, expected 99"); |
|---|
| 376 |
i+=6; |
|---|
| 377 |
foreach (val;[&kiss_x,&kiss_y,&kiss_z,&kiss_c,&nBytes,&restB]){ |
|---|
| 378 |
assert(s[i]=='_',"no separator _ found"); |
|---|
| 379 |
++i; |
|---|
| 380 |
uint ate; |
|---|
| 381 |
*val=cast(uint)Integer.convert(s[i..i+8],16,&ate); |
|---|
| 382 |
assert(ate==8,"unexpected read size"); |
|---|
| 383 |
i+=8; |
|---|
| 384 |
} |
|---|
| 385 |
return i; |
|---|
| 386 |
} |
|---|
| 387 |
} |
|---|
| 388 |
|
|---|
| 389 |
/+ like Kiss99, but synchronized, so multiple thread access is ok |
|---|
| 390 |
+ (but if you need multiple thread access think about having a random number generator per thread) |
|---|
| 391 |
+ This is the engine, *never* use it directly, always use it though a RandomG class |
|---|
| 392 |
+/ |
|---|
| 393 |
struct Kiss99Sync{ |
|---|
| 394 |
uint kiss_x = 123456789; |
|---|
| 395 |
uint kiss_y = 362436000; |
|---|
| 396 |
uint kiss_z = 521288629; |
|---|
| 397 |
uint kiss_c = 7654321; |
|---|
| 398 |
uint nBytes = 0; |
|---|
| 399 |
uint restB = 0; |
|---|
| 400 |
Mutex lock; |
|---|
| 401 |
|
|---|
| 402 |
const int canCheckpoint=true; |
|---|
| 403 |
const int canSeed=true; |
|---|
| 404 |
|
|---|
| 405 |
void skip(uint n){ |
|---|
| 406 |
for (int i=n;i!=n;--i){ |
|---|
| 407 |
next; |
|---|
| 408 |
} |
|---|
| 409 |
} |
|---|
| 410 |
ubyte nextB(){ |
|---|
| 411 |
if (nBytes>0) { |
|---|
| 412 |
ubyte res=cast(ubyte)(restB & 0xFF); |
|---|
| 413 |
restB >>= 8; |
|---|
| 414 |
--nBytes; |
|---|
| 415 |
return res; |
|---|
| 416 |
} else { |
|---|
| 417 |
restB=next; |
|---|
| 418 |
ubyte res=cast(ubyte)(restB & 0xFF); |
|---|
| 419 |
restB >>= 8; |
|---|
| 420 |
nBytes=3; |
|---|
| 421 |
return res; |
|---|
| 422 |
} |
|---|
| 423 |
} |
|---|
| 424 |
uint next(){ |
|---|
| 425 |
uint res; |
|---|
| 426 |
const ulong a = 698769069UL; |
|---|
| 427 |
ulong t; |
|---|
| 428 |
synchronized(lock){ |
|---|
| 429 |
kiss_x = 69069*kiss_x+12345; |
|---|
| 430 |
kiss_y ^= (kiss_y<<13); kiss_y ^= (kiss_y>>17); kiss_y ^= (kiss_y<<5); |
|---|
| 431 |
t = a*kiss_z+kiss_c; kiss_c = (t>>32); |
|---|
| 432 |
kiss_z=cast(uint)t; |
|---|
| 433 |
res=kiss_x+kiss_y+kiss_z; |
|---|
| 434 |
} |
|---|
| 435 |
return res; |
|---|
| 436 |
} |
|---|
| 437 |
ulong nextL(){ |
|---|
| 438 |
return ((cast(ulong)next)<<32)+cast(ulong)next; |
|---|
| 439 |
} |
|---|
| 440 |
|
|---|
| 441 |
void seed(uint delegate() r){ |
|---|
| 442 |
if (!lock) lock=new Mutex(); |
|---|
| 443 |
synchronized(lock){ |
|---|
| 444 |
kiss_x = r(); |
|---|
| 445 |
for (int i=0;i<100;++i){ |
|---|
| 446 |
kiss_y=r(); |
|---|
| 447 |
if (kiss_y!=0) break; |
|---|
| 448 |
} |
|---|
| 449 |
if (kiss_y==0) kiss_y=362436000; |
|---|
| 450 |
kiss_z=r(); |
|---|
| 451 |
/* Donât really need to seed c as well (is reset after a next), |
|---|
| 452 |
but doing it allows to completely restore a given internal state */ |
|---|
| 453 |
kiss_c = r() % 698769069; /* Should be less than 698769069 */ |
|---|
| 454 |
nBytes=0; |
|---|
| 455 |
restB=0; |
|---|
| 456 |
} |
|---|
| 457 |
} |
|---|
| 458 |
/// IWritable implementation |
|---|
| 459 |
void write (IWriter input){ |
|---|
| 460 |
synchronized(lock){ |
|---|
| 461 |
input(kiss_x)(kiss_y)(kiss_z)(kiss_c)(nBytes)(restB); |
|---|
| 462 |
} |
|---|
| 463 |
} |
|---|
| 464 |
/// IReadable implementation |
|---|
| 465 |
void read (IReader input){ |
|---|
| 466 |
synchronized(lock){ |
|---|
| 467 |
input(kiss_x)(kiss_y)(kiss_z)(kiss_c)(nBytes)(restB); |
|---|
| 468 |
} |
|---|
| 469 |
} |
|---|
| 470 |
/// writes the current status in a string |
|---|
| 471 |
char[] toString(){ |
|---|
| 472 |
char[] res=new char[6+6*9]; |
|---|
| 473 |
int i=0; |
|---|
| 474 |
res[i..i+6]="KISS99"; |
|---|
| 475 |
i+=6; |
|---|
| 476 |
synchronized(lock){ |
|---|
| 477 |
foreach (val;[kiss_x,kiss_y,kiss_z,kiss_c,nBytes,restB]){ |
|---|
| 478 |
res[i]='_'; |
|---|
| 479 |
++i; |
|---|
| 480 |
Integer.format(res[i..i+8],val,"x8"); |
|---|
| 481 |
i+=8; |
|---|
| 482 |
} |
|---|
| 483 |
} |
|---|
| 484 |
assert(i==res.length,"unexpected size"); |
|---|
| 485 |
return res; |
|---|
| 486 |
} |
|---|
| 487 |
/// reads the current status from a string (that should have been trimmed) |
|---|
| 488 |
/// returns the number of chars read |
|---|
| 489 |
uint fromString(char[] s){ |
|---|
| 490 |
uint i=0; |
|---|
| 491 |
assert(s[i..i+4]=="KISS","unexpected kind, expected KISS"); |
|---|
| 492 |
assert(s[i+4..i+7]=="99_","unexpected version, expected 99"); |
|---|
| 493 |
i+=6; |
|---|
| 494 |
synchronized(lock){ |
|---|
| 495 |
foreach (val;[&kiss_x,&kiss_y,&kiss_z,&kiss_c,&nBytes,&restB]){ |
|---|
| 496 |
assert(s[i]=='_',"no separator _ found"); |
|---|
| 497 |
++i; |
|---|
| 498 |
uint ate; |
|---|
| 499 |
*val=cast(uint)Integer.convert(s[i..i+8],16,&ate); |
|---|
| 500 |
assert(ate==8,"unexpected read size"); |
|---|
| 501 |
i+=8; |
|---|
| 502 |
} |
|---|
| 503 |
} |
|---|
| 504 |
return i; |
|---|
| 505 |
} |
|---|
| 506 |
} |
|---|
| 507 |
|
|---|
| 508 |
/// ziggurat method for decreasing distributions. |
|---|
| 509 |
/// Marsaglia, Tsang, Journal of Statistical Software, 2000 |
|---|
| 510 |
/// If has negative is true the distribution is assumed to be symmetric with respect to 0, |
|---|
| 511 |
/// otherwise it is assumed to be from 0 to infinity. |
|---|
| 512 |
/// Struct based to avoid extra indirection when wrapped in a class (and it should be wrapped |
|---|
| 513 |
/// in a class and not used directly). |
|---|
| 514 |
/// Call style initialization avoided on purpose (this is a big structure, you don't want to return it) |
|---|
| 515 |
struct Ziggurat(RandG,T,alias probDensityF,alias tailGenerator,bool hasNegative=true){ |
|---|
| 516 |
static assert(isFloat!(T),T.stringof~" not acceptable, only floating point variables supported"); |
|---|
| 517 |
const int nBlocks=256; |
|---|
| 518 |
T[nBlocks+1] posBlock; |
|---|
| 519 |
T[nBlocks+1] fVal; |
|---|
| 520 |
RandG r; |
|---|
| 521 |
alias Ziggurat SourceT; |
|---|
| 522 |
/// initializes the ziggurat |
|---|
| 523 |
static Ziggurat create(alias invProbDensityF, alias cumProbDensityFCompl)(RandG rGenerator,real xLast=-1.0L,bool check_error=true){ |
|---|
| 524 |
/// function to find xLast |
|---|
| 525 |
real findXLast(real xLast){ |
|---|
| 526 |
real v=xLast*probDensityF(xLast)+cumProbDensityFCompl(xLast); |
|---|
| 527 |
real fMax=probDensityF(0.0L); |
|---|
| 528 |
real pAtt=xLast; |
|---|
| 529 |
real fAtt=probDensityF(xLast); |
|---|
| 530 |
for (int i=nBlocks-2;i!=0;--i){ |
|---|
| 531 |
fAtt+=v/pAtt; |
|---|
| 532 |
if (fAtt>fMax) return fAtt+(i-1)*fMax; |
|---|
| 533 |
pAtt=invProbDensityF(fAtt); |
|---|
| 534 |
assert(pAtt>=0,"invProbDensityF is supposed to return positive values"); |
|---|
| 535 |
} |
|---|
| 536 |
return fAtt+v/pAtt-fMax; |
|---|
| 537 |
} |
|---|
| 538 |
void findBracket(ref real xMin,ref real xMax){ |
|---|
| 539 |
real vMin=cumProbDensityFCompl(0.0L)/nBlocks; |
|---|
| 540 |
real pAtt=0.0L; |
|---|
| 541 |
for (int i=1;i<nBlocks;++i){ |
|---|
| 542 |
pAtt+=vMin/probDensityF(pAtt); |
|---|
| 543 |
} |
|---|
| 544 |
real df=findXLast(pAtt); |
|---|
| 545 |
if (df>0) { |
|---|
| 546 |
// (most likely) |
|---|
| 547 |
xMin=pAtt; |
|---|
| 548 |
real vMax=cumProbDensityFCompl(0.0L); |
|---|
| 549 |
xMax=pAtt+vMax/probDensityF(pAtt); |
|---|
| 550 |
} else { |
|---|
| 551 |
xMax=pAtt; |
|---|
| 552 |
xMin=vMin/probDensityF(0.0L); |
|---|
| 553 |
} |
|---|
| 554 |
} |
|---|
| 555 |
if (xLast<=0){ |
|---|
| 556 |
real xMin,xMax; |
|---|
| 557 |
findBracket(xMin,xMax); |
|---|
| 558 |
xLast=findRoot(&findXLast,xMin,xMax); |
|---|
| 559 |
// printf("xLast:%La => %La\n",xLast,findXLast(xLast)); |
|---|
| 560 |
} |
|---|
| 561 |
Ziggurat res; |
|---|
| 562 |
with (res){ |
|---|
| 563 |
r=rGenerator; |
|---|
| 564 |
real v=probDensityF(xLast)*xLast+cumProbDensityFCompl(xLast); |
|---|
| 565 |
real pAtt=xLast; |
|---|
| 566 |
real fMax=probDensityF(0.0L); |
|---|
| 567 |
posBlock[1]=cast(T)xLast; |
|---|
| 568 |
real fAtt=probDensityF(xLast); |
|---|
| 569 |
fVal[1]=cast(T)fAtt; |
|---|
| 570 |
for (int i=2;i<nBlocks;++i){ |
|---|
| 571 |
fAtt+=v/pAtt; |
|---|
| 572 |
assert(fAtt<=fMax,"Ziggurat contruction shoot out"); |
|---|
| 573 |
pAtt=invProbDensityF(fAtt); |
|---|
| 574 |
assert< |
|---|