From: Jonathan Lee on
On Apr 14, 2:53 pm, Jonathan Lee <cho...(a)shaw.ca> wrote:
> On Apr 14, 2:06 pm, Dann Corbit <dcor...(a)connx.com> wrote:
>
> Thanks for sharing.
>
> Isn't this dangerous for y:
>

Just confirmed: if y isn't masked to 32-bits the output
is wrong.

Anyway, here's my take on the code:

// kiss2.hpp
-------------------------------------------------------------------
#include <cstddef>

class kiss2 {
double Q[1220]; // meh.. I guess this could be a
std::vector
const std::size_t qlen; // length of Q array
std::size_t indx;
double c; // current CSWB
double zc; // current SWB `borrow`
double zx; // SWB seed1
double zy; // SWB seed2
public:
kiss2(unsigned long = 123456789UL, unsigned long = 362436069UL);
double operator()(); // For getting a random number
};

// kiss2.cpp
-------------------------------------------------------------------
//#include "kiss2.hpp"
#include <cfloat>
using std::size_t;
/**
\todo? Replace constant initialization of indx and qlen w/ sizeof Q/
sizeof Q[0]
\todo Magic numbers make me uneasy (re: zx, zy)
*/
kiss2::kiss2(
unsigned long x, // seed1 value
unsigned long y // seed2 value
): qlen(1220), indx(1220), c(0.0), zc(0.0),
zx(5212886298506819.0 / 9007199254740992.0),
zy(2020898595989513.0 / 9007199254740992.0)
{
#if (FLT_RADIX != 2 || DBL_MIN_EXP > -53)
#error "Machine double not supported"
#endif

// fill in Q[i] "using 9th bit from Cong+Xorshift"
for (size_t i = 0; i < qlen; i++) {
double s = 0.0, t = 1.0;

// Build Q[i] one bit at a time
for (int j = 0; j < 52; j++) {
t *= 0.5; // make t=.5/2^j
x = (69069 * x + 123);
y = (y ^ (y << 13)) & 0xFFFFFFFFUL;
y = (y ^ (y >> 17)) & 0xFFFFFFFFUL;
y = (y ^ (y << 5)) & 0xFFFFFFFFUL;

if (((x + y) >> 23) & 1UL) // conditionally set bit of s
s += t;
}
Q[i] = s;
}
}

/**
\todo Separate refill function?
\todo I guess we sorta need a guarantee that qlen >= 30
*/
double kiss2::operator()() { // Takes 14 nanosecs, Intel Q6600,2.40GHz
static const double cc = 1.0 / 9007199254740992.0; // 2^-53

double t; // t: first temp, then next CSWB value
// First get zy as next lag-2 SWB
t = zx - zy - zc;
zx = zy;
if (t < 0) {
zy = t + 1.0, zc = cc;
} else zy = t, zc = 0.0;

// Then get t as the next lag-1220 CSWB value
if (indx >= qlen) { // refill Q[n] via Q[n-1220]-Q[n-1190]-c
for (size_t i = 0; i < qlen; i++) {
size_t j = (i < 30) ? i + (qlen - 30) : i - 30;
t = Q[j] - Q[i] + c; // Get next CSWB element
if (t > 0) {
t = t - cc, c = cc;
} else t = t - cc + 1.0, c = 0.0;
Q[i] = t;
}
indx = 0; // reset indx
}

// return Q[indx] - zy (mod 1)
t = Q[indx++] - zy;
return (t < 0.0 ? 1.0 + t : t);
}

// main.cpp
--------------------------------------------------------------------
#include <cstdio>
#include <cstdlib>
// #include "kiss2.hpp"
int main(void)
{ /* You must provide at least two 32-bit seeds */
kiss2 krng; // Use the default seeds
double t;
int i;
for (i = 0; i < 1000000000; i++)
t = krng();
printf ("%.16f\n", krng());
}

--Jonathan
From: rossum on
On Wed, 14 Apr 2010 03:41:05 -0700 (PDT), geo <gmarsaglia(a)gmail.com>
wrote:

>1. Simple and very fast, some 70 million double-precision
> uniform(0,1] random variables/second, in IEEE 754 standard
> form
This gives an issue with the Java conversion. Java expects the return
from Random.nextDouble() to be in the range [0.0, 1.0), while this
code produces numbers in the range (0.0, 1.0].

I know I can make the switch by using:

return (1.0 - DoubleKISS());

Does anyone have any alternative suggestions that are faster and do
not break George's excellent RNG.

rossum

From: steve on
On Apr 15, 7:04 am, rossum <rossu...(a)coldmail.com> wrote:
> On Wed, 14 Apr 2010 03:41:05 -0700 (PDT), geo <gmarsag...(a)gmail.com>
> wrote:
>
> >1. Simple and very fast, some 70 million double-precision
> >   uniform(0,1] random variables/second, in IEEE 754 standard
> >   form
>
> This gives an issue with the Java conversion.  Java expects the return
> from Random.nextDouble() to be in the range [0.0, 1.0), while this
> code produces numbers in the range (0.0, 1.0].
>
> I know I can make the switch by using:
>
>   return (1.0 - DoubleKISS());
>
> Does anyone have any alternative suggestions that are faster and do
> not break George's excellent RNG.

Not sure if it would be faster, but one could do

return(nextafter(DoubleKISS(), -1.));

Two items that George did not comment on are subnormal
numbers and how he determined the distribution is normal
over (0,1]. Does his generator create subnormals? If
I understand Figure D-1 in Goldberg, "What every computer
scientist should know about floating-point arithmetic,"
the distribution cannot be normal.
From: rossum on
On Wed, 14 Apr 2010 03:41:05 -0700 (PDT), geo <gmarsaglia(a)gmail.com>
wrote:

>for(i=0;i<1000000000;i++) t=dUNI();
>printf("%.16f\n",dUNI());
>}
>
>/*
>Output, after 10^9 random uniforms:
> 0.6203646342357479
Small mistake here George. You get 0.6203646342357479 after (10^9) +
1 random uniforms because there is an extra call to dUNI() in the
printf statement.

Took me a while to find, as my code had the equivalent of:
printf("%.16f\n",t);
and I couldn't find my mistake anywhere in the dUNI() code.

I get:
0.7976863625406643 after 1,000,000,000 calls
0.6203646342357480 after 1,000,000,001 calls

rossum

From: geo on
On Apr 15, 10:35 am, steve <kar...(a)comcast.net> wrote:
> On Apr 15, 7:04 am, rossum <rossu...(a)coldmail.com> wrote:
>
>
>
>
>
> > On Wed, 14 Apr 2010 03:41:05 -0700 (PDT), geo <gmarsag...(a)gmail.com>
> > wrote:
>
> > >1. Simple and very fast, some 70 million double-precision
> > >   uniform(0,1] random variables/second, in IEEE 754 standard
> > >   form
>
> > This gives an issue with the Java conversion.  Java expects the return
> > from Random.nextDouble() to be in the range [0.0, 1.0), while this
> > code produces numbers in the range (0.0, 1.0].
>
> > I know I can make the switch by using:
>
> >   return (1.0 - DoubleKISS());
>
> > Does anyone have any alternative suggestions that are faster and do
> > not break George's excellent RNG.
>
> Not sure if it would be faster, but one could do
>
>    return(nextafter(DoubleKISS(), -1.));
>
> Two items that George did not comment on are subnormal
> numbers and how he determined the distribution is normal
> over (0,1].  Does his generator create subnormals?  If
> I understand Figure D-1 in Goldberg, "What every computer
> scientist should know about floating-point arithmetic,"
> the distribution cannot be normal.- Hide quoted text -
>
> - Show quoted text -

Users who insist on getting every possible float
in the unit interval could form dUNI()*.5^j;
with j taking values
0, 1, 2, 3,...
with probabilities
q, qp, qp^2, qp^3, ...
and p = 2^{-53) and q = 1-p..
Even at the rate of 70 million per second,
you wouild have to wait an average of over
four years before you had to multiply by .5,
8 years to multiply by .5^2, etc..

George Marsaglia