Question

I need a PRNG for a simulation project, and found a resource which, given my limited but not nonexistent knowledge of PRNG's seems sound and well-informed. I'm trying to encapsulate the algorithms given in this report in a class, but for some reason I get a lot of repeated values. It might just be that the PRNG isn't as good as the report states it is, but I suspect that it's rather something in my implementation that fails.

Background: PRNG code from the report

The following code sample is given on page 3:

/* Public domain code for JKISS RNG */
// seed variables
static unsigned int x = 123456789,y = 987654321,z = 43219876,c = 6543217;

unsigned int JKISS()
{
    unsigned long long t;
    x = 314527869 * x + 1234567;
    y ^= y << 5; y ^= y >> 7; y ^= y << 22;
    t = 4294584393ULL * z + c; c = t >> 32; z = t;
    return x + y + z;
}

In connection with it, the report claims that

The period of JKISS is ≈2 127 = 1.7x10 38 (2 32 x (2 32 -1) x (1/2 * 4294584393 x 2 32 - 1)) and it passes all of the Dieharder tests and the complete BigCrunch test set in TestU01.

so this definitely seems good enough to me. Later in the report (page 6), it is stated

The following C code generate [sic] a random (double precision) floating point number 0 <= x < 1:

double x;
x = JKISS() / 4294967296.0;

My encapsulation of this in a class

I have the following in a header file:

class JKISS : public IPRNG {
private:
    // Seed variables
    static unsigned int x;
    static unsigned int y;
    static unsigned int z;
    static unsigned int c;


public:
    static unsigned int randui32();
    static double randdouble();
};

with the following implementation file

#include "prng.hpp"

unsigned int JKISS::x = 123456789;
unsigned int JKISS::y = 987654321;
unsigned int JKISS::z = 43219876;
unsigned int JKISS::c = 6543217;

unsigned int JKISS::randui32() {
    unsigned long long t;
    x = 314527869 * x + 1234567;
    y ^= y << 5; y ^= y >> 7; y ^= y << 22;
    t = 4294584393ULL * z + c; c = t >> 32; z = t;
    return x + y + z;
}

double JKISS::randdouble() {
    return randui32() / 4294967296.0;
}

and the following main program

#include <iostream>
#include "prng.hpp"

int main() {
    for (int i = 0; i < 10000; ++i) {
        std::cout << JKISS::randdouble() << std::endl;
    }
}

As you can see, I've copy-pasted most of the code.

However, when I run this, I get 68 repeated values, even though I'm just fetching 10 000 values. This suggests to me that something is wrong with my encapsulation, but I can't figure out what the problem is.

In case it matters, I'm running GCC 4.8.1 on Ubuntu 13.10 with the following specs:

Platform Info:
  System: Linux (x86_64-linux-gnu)
  CPU: Intel(R) Xeon(R) CPU           E5410  @ 2.33GHz
  WORD_SIZE: 64

Any ideas as to what could cause this are most welcome.

Was it helpful?

Solution 2

I get the same results as you do, but no duplicates ;p

What I mean is that if I run your program as directed I get 68 duplicates, but if I switch randdouble() => randui32() there are no more duplicates, so I'll bet they were an artifact due to the precision of the printing routine.

You could try to collect the doubles in an array and compare to make 100% sure.

OTHER TIPS

You are returning a float, while the original code generates a double.

What for? What makes you think that some random page on the 'web will give you a better RNG than the ones built-in to your C++ standard library, which provides all sorts of nifty features packaged up and ready for use? Are you really in position to avaluate if what you found is better for your purposes?

It looks like the printed output is only six significant figures, which means that you have something like 1000000 unique display values (this is oversimplified -- there are more possibilities but the distribution is skewed). In effect you print 10000 values from a pool of 1000000. I think 68 duplicates is reasonable in that situation.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top