views:

1740

answers:

7

I am looking for a pseudo random number generator which would be specialized to work fast when it is given a seed before generating each number. Most generators I have seen so far assume you set seed once and then generate a long sequence of numbers. The only thing which looks somewhat similar to I have seen so far is Perlin Noise, but it generates too "smooth" data - for similar inputs it tends to produce similar results.

The declaration of the generator should look something like:

int RandomNumber1(int seed);

Or:

int RandomNumber3(int seedX, int seedY, int seedZ);

I think having good RandomNumber1 should be enough, as it is possible to implement RandomNumber3 by hashing its inputs and passing the result into the RandomNumber1, but I wrote the 2nd prototype in case some implementation could use the independent inputs.

The intended use for this generator is to use it for procedural content generator, like generating a forest by placing trees in a grid and determining a random tree species and random spatial offsets for each location.

The generator needs to be very efficient (below 500 CPU cycles), because the procedural content is created in huge quantities in real time during rendering.

+12  A: 

Seems like you're asking for a hash-function rather than a PRNG. Googling 'fast hash function' yields several promising-looking results.

For example:

uint32_t hash( uint32_t a)
    a = (a ^ 61) ^ (a >> 16);
    a = a + (a << 3);
    a = a ^ (a >> 4);
    a = a * 0x27d4eb2d;
    a = a ^ (a >> 15);
    return a;
}

Edit: Yep, some hash functions definitely look more suitable than others.

For your purposes, it should be sufficient to eyeball thefunction and check that a single-bit change in the input will propagate to lots of output bits.

I hope this is a good direction to go. At first look it seems to me while hash functions do have one important property (uniform distribution), I am not quite sure if its output can be considered "random" - how do I know for a particular function how much does its output resemble noise?
Suma
One test for a good hash function is to give it the sequence of integers 0, 1, 2.. and test the output for 'randomness' using pseudo random number generator tests.
Aaron
+8  A: 

Yep, you are looking for a fast integer hash algorithm rather than a PRNG.

This page has a few algorithms, I'm sure you'll find plenty more now you know the correct search terms.

Matt Howells
Offtopic: Don't suppose you're from Palmer's Green by any chance?
Nope, you must know a different Matt Howells!
Matt Howells
+2  A: 

see std::tr1::ranlux3, or other random number generators that are part of TR1 additions to the standard C++ library. I suggested mt19937 initialially, but then saw your note that it needs to be very fast. TR1 is should be available on Microsoft VC++ and GCC, and can also be found in the boost libraries which support even more compilers.

example adapted from boost documentation:

#include <random>
#include <iostream>
#include <iterator>
#include <functional>
#include <algorithm>
#include <ctime>
using namespace std;
using namespace std::tr1;
int main(){
    random_device trueRand;
    ranlux3 rng(trueRand);  // produces randomness out of thin air
                            // see pseudo-random number generators
    uniform_int<> six(1,6); // distribution that maps to 1..6
                            // see random number distributions
    variate_generator<ranlux3&, uniform_int<> >
           die(rng, six);   // glues randomness with mapping

    // simulate rolling a die
    generate_n( ostream_iterator<int>(cout, " "), 10, ref(die));
}

example output:

2 4 4 2 4 5 4 3 6 2

Any TR1 random number generator can seed any other random number generator. If you need higher quality results, consider feeding the output of mt19937 (which is slower, but higher quality) into a minstd_rand or randlux3, which are faster generators.

Aaron
A: 

If memory is not really an issue and speed is of utmost importance then you can prebuild a large array of random numbers and just iterate through it at runtime. For example have a seperate program generate 100,000 random numbers and save it as it's own file like

unsigned int randarray []={1,2,3,....}

then include that file into your compile and at runtime your random number function only needs to pull numbers from that array and loop back to the start when it hits the end.

KPexEA
Computing a simple hash as in http://stackoverflow.com/questions/167735/#167764 will almost always be faster than accessing a huge array (huge array will not fit into the cache, therefore accessing it is slow)
Suma
I just profiled it on my PC and using my lookup table method vs the hash function, the lookup table is 13x faster.
KPexEA
The lookup table can be faster when it is small enough to fit into L2 cache, and when you are not using the L2 cache for anything else - which was most likely the case in your test. If you want to test real world performance, you need to perform some significant data processing between the lookups.
Suma
+2  A: 

Here's a small random number generator developed by George Marsaglia. He's an expert in the field, so you can be confident the generator has good statistical properties.

v = 36969*(v & 65535) + (v >> 16);
u = 18000*(u & 65535) + (u >> 16);
return (v << 16) + u;

Here u and v are unsigned ints. Initialize them to any non-zero values. Each time you generate a random number, store u and v somewhere. You could wrap this in a function to match your signature above (except the ints are unsigned.)

John D. Cook
Unfortunately this does not match the question. I need to provide my own U and V each time, not to have them stored somewhere and updated between iterations. The function needs to always produce the same output given the same inputs.
Suma
@Suma: Why can't you provide your own U and V each time if you just pass them as parameters to this function? And having the same U and same V each time will also always produce the same result. It matches your question exactly!
Mecki
A: 

Marsaglia's PRNG above has a typo: it needs (u & 65535) in the code. See Marsaglia's post:

http://www.math.uni-bielefeld.de/~sillke/ALGORITHMS/random/marsaglia-c

A: 

I use the following code in my Java random number library - this has worked pretty well for me. I also use this for generating procedural content.

/**
 * State for random number generation
 */
private static volatile long state=xorShift64(System.nanoTime()|0xCAFEBABE);

/**
 * Gets a long random value
 * @return Random long value based on static state
 */
public static long nextLong() {
 long a=state;
 state = xorShift64(a);
 return a;
}

/**
 * XORShift algorithm - credit to George Marsaglia!
 * @param a initial state
 * @return new state
 */
public static final long xorShift64(long a) {
 a ^= (a << 21);
 a ^= (a >>> 35);
 a ^= (a << 4);
 return a;
}
mikera