123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
|
/*******************************************************************************
copyright: Copyright (c) 2008. All rights reserved
license: BSD style: $(LICENSE)
version: Initial release: May 2008
author: Various
Since: 0.99.7
With gratitude to Dr Jurgen A Doornik. See his paper entitled
"Conversion of high-period random numbers to floating point"
*******************************************************************************/
module tango.math.random.Kiss;
version (Win32)
private extern(Windows) int QueryPerformanceCounter (ulong *);
version (Posix)
{
private import tango.stdc.posix.sys.time;
}
/******************************************************************************
KISS (from George Marsaglia)
The idea is to use simple, fast, individually promising
generators to get a composite that will be fast, easy to code
have a very long period and pass all the tests put to it.
The three components of KISS are
---
x(n)=a*x(n-1)+1 mod 2^32
y(n)=y(n-1)(I+L^13)(I+R^17)(I+L^5),
z(n)=2*z(n-1)+z(n-2) +carry mod 2^32
---
The y's are a shift register sequence on 32bit binary vectors
period 2^32-1; The z's are a simple multiply-with-carry sequence
with period 2^63+2^32-1. The period of KISS is thus
---
2^32*(2^32-1)*(2^63+2^32-1) > 2^127
---
Note that this should be passed by reference, unless you really
intend to provide a local copy to a callee
******************************************************************************/
struct Kiss
{
///
public alias natural toInt;
///
public alias fraction toReal;
private uint kiss_k;
private uint kiss_m;
private uint kiss_x = 1;
private uint kiss_y = 2;
private uint kiss_z = 4;
private uint kiss_w = 8;
private uint kiss_carry = 0;
private enum double M_RAN_INVM32 = 2.32830643653869628906e-010,
M_RAN_INVM52 = 2.22044604925031308085e-016;
/**********************************************************************
A global, shared instance, seeded via startup time
**********************************************************************/
public static __gshared Kiss instance;
shared static this ()
{
instance.seed();
}
/**********************************************************************
Creates and seeds a new generator with the current time
**********************************************************************/
static Kiss opCall ()
{
Kiss rand;
rand.seed();
return rand;
}
/**********************************************************************
Seed the generator with current time
**********************************************************************/
void seed ()
{
ulong s;
version (Posix)
{
timeval tv;
gettimeofday (&tv, null);
s = tv.tv_usec;
}
version (Win32)
QueryPerformanceCounter (&s);
return seed (cast(uint) s);
}
/**********************************************************************
Seed the generator with a provided value
**********************************************************************/
void seed (uint seed)
{
kiss_x = seed | 1;
kiss_y = seed | 2;
kiss_z = seed | 4;
kiss_w = seed | 8;
kiss_carry = 0;
}
/**********************************************************************
Returns X such that 0 <= X <= uint.max
**********************************************************************/
uint natural ()
{
kiss_x = kiss_x * 69069 + 1;
kiss_y ^= kiss_y << 13;
kiss_y ^= kiss_y >> 17;
kiss_y ^= kiss_y << 5;
kiss_k = (kiss_z >> 2) + (kiss_w >> 3) + (kiss_carry >> 2);
kiss_m = kiss_w + kiss_w + kiss_z + kiss_carry;
kiss_z = kiss_w;
kiss_w = kiss_m;
kiss_carry = kiss_k >> 30;
return kiss_x + kiss_y + kiss_w;
}
/**********************************************************************
Returns X such that 0 <= X < max
Note that max is exclusive, making it compatible with
array indexing
**********************************************************************/
uint natural (uint max)
{
return natural() % max;
}
/**********************************************************************
Returns X such that min <= X < max
Note that max is exclusive, making it compatible with
array indexing
**********************************************************************/
uint natural (uint min, uint max)
{
return (natural() % (max-min)) + min;
}
/**********************************************************************
Returns a value in the range [0, 1) using 32 bits
of precision (with thanks to Dr Jurgen A Doornik)
**********************************************************************/
double fraction ()
{
return ((cast(int) natural()) * M_RAN_INVM32 + (0.5 + M_RAN_INVM32 / 2));
}
/**********************************************************************
Returns a value in the range [0, 1) using 52 bits
of precision (with thanks to Dr Jurgen A Doornik)
**********************************************************************/
double fractionEx ()
{
return ((cast(int) natural()) * M_RAN_INVM32 + (0.5 + M_RAN_INVM52 / 2) +
((cast(int) natural()) & 0x000FFFFF) * M_RAN_INVM52);
}
}
/******************************************************************************
******************************************************************************/
debug (Kiss)
{
import tango.io.Stdout;
import tango.time.StopWatch;
void main()
{
auto dbl = Kiss();
auto count = 100_000_000;
StopWatch w;
w.start;
double v1;
for (int i=count; --i;)
v1 = dbl.fraction;
Stdout.formatln ("{} fraction, {}/s, {:f10}", count, count/w.stop, v1);
w.start;
for (int i=count; --i;)
v1 = dbl.fractionEx;
Stdout.formatln ("{} fractionEx, {}/s, {:f10}", count, count/w.stop, v1);
for (int i=count; --i;)
{
auto v = dbl.fraction;
if (v <= 0.0 || v >= 1.0)
{
Stdout.formatln ("fraction {:f10}", v);
break;
}
v = dbl.fractionEx;
if (v <= 0.0 || v >= 1.0)
{
Stdout.formatln ("fractionEx {:f10}", v);
break;
}
}
}
}
|