views:

246

answers:

7

After profiling a large game playing program, I have found that the library function rand() is consuming a considerable fraction of the total processing time. My requirements for the random number generator are not very onerous - its not important that it pass a great battery of statistical tests of pure randomness. I just want something cheap and cheerful that is very fast. Any suggestions?

+4  A: 

You are probably looking for a linear congruential generator.

kotlinski
Note that `rand()` is almost universally implemented as such (that is: I have yet to see an stdlib implementation that *doesn't* use a crappy LCG).
Joey
+1 for the link. It offers information and resources about other algorithms also.
Iulian Şerbănoiu
Johannes: Even if that is true, libraries usually add overhead to ensure thread correctness. (The same number series should be generated no matter how many threads are running.)
kotlinski
...I don't think anything in the standard requires that behavior, but in my experience, rand() is usually thread correct.
kotlinski
@kotlinski: There are two approaches to handling threads: either locking is added so that all threads use a single stream of random numbers, or every thread gets its own RNG (and that can be lock-free, at a cost of more memory). I mostly prefer to avoid locks, keeping threads in their own isolated worlds as much as possible, but I can understand people preferring the other approach.
Donal Fellows
+2  A: 

You can use some pre-calculated values for random numbers and store them in some arrays. The RNG algorithms are not a very easy task to do. If you need just a small amount of random numbers then this is a solution in my opinion.

Usually in games there is a lot of pre-calculation (sin/cos values and other stuff that is used very often inside a video game and it would consume a lot of CPU cycles if not pre-calculated).

You can also look at HW RNG but I believe this is out of the question.

Iulian Şerbănoiu
The main reason to ignore hardware RNGs is that most people don't have them installed. This is particularly true for gaming systems.
Donal Fellows
@Donal Fellows This is so true, but it is possible in case of a diploma project that he will get such device if the allocated budget allows it.
Iulian Şerbănoiu
This is a really bad idea. 1) You waste space. 2) You will get an extra cache miss for each call to rand()
kotlinski
Would this have less performance than a rand() call? We're comparing a call to rand() with a memory access. I believe the rand() call should be slower. Am I wrong?
Iulian Şerbănoiu
Maybe not slower than rand() (this depends on the stdlib rand()) but there are more efficient solutions.
kotlinski
The code for an LCRNG could well fit inside cache. An external device won't be cached at any level, by definition.
Donal Fellows
Hardware RNGs are usually only brought in when needing high-quality unpredictable random numbers. Mostly used nowadays for speeding up servers that process many SSL connections. And that's a problem of limited entropy in a normal computer, not a problem of limited processing power :-)
Joey
@Iulian: Plus he doesn't say that it's a diploma project. Doing a roll-out of a hardware RNG in production is difficult (check your own wikipedia link for things that can go subtly wrong) and so is best only done where a very high quality RNG is required. An example where it is needed is in production of master keypairs for banking applications. For gaming, you really don't need that quality. In fact, for gaming you can probably even get away without a simulation-grade RNG, since most of the “randomness” will be actually reacting to the situation. An LCRNG will do just fine.
Donal Fellows
+3  A: 

There are few algorithms in common use that are faster than an LCG (which is very, very likely what rand() is using). You may want to try Marsaglia's Xorshift generator which is pretty fast (depending on the hardware). The WELL512a generator is also quite fast (more so than MT19937 or MT19937-64).

Joey
Question: Which of the two alternatives that you suggest is the 'accepted' answer? And which do you recommend?
Joseph Quinsey
@Joseph: I can't reliably tell. The vast majority of pseudo-random number generators are very similar in speed when implemented on software, some designs lend themselves for very efficient hardware implementation as well. So the largest performance differences are probably coming down to architecture differences and at least in simulations I know that PRNGs are very rarely if ever the performance problem. Xorshift is sometimes (Numerical Recipes) recommended only as a building block for building a combined generator, while WELL is designed to be used as is. I'd use the latter, personally.
Joey
I selected xorshift because the source code was right there in the first link and I didn't have to dig around for it.
Mick
A: 

This may not be a great answer, and is really more of a question.

Depending on the platform and the frequency of depending on the value, wouldn't the least significant numbers of a microsecond returning function approximate something 'random'?

unomi
A: 

The Mersenne Twister is said to be faster than many RAND implementations, but YMMV depending on implementation details and hardware.

Kramii
For me in Java on x86 it's slightly slower. On modern architectures SFMT is a quite good solution, though. Also it takes quite a while to initialize the 623-word state and that's a performance hit you'll feel in unpredictable intervals (well, predictably every 623 random numbers, but still).
Joey
+1  A: 

Since you didn't say much about your implementation, if this is multithreaded using a function that uses a global state is almost always a bad idea. Many implementations then just use mutexes to protect concurrent access. The long times that you would observe then would just be waiting times and not the computation of the rand function itself. POSIX has the rand48 family of functions that also have reentrant versions that should do better on concurrent access, see http://opengroup.org/onlinepubs/007908799/xsh/drand48.html

Jens Gustedt
+1  A: 

Here's one I wrote for Java based on Marsaglia's XORShift algorithm that you could probably adapt. Works beautifully for my purposes (game development, simulation).

/**
 * 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 final 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