Hello JGO Community
While browsing around these forums, lately i’ve encountered alot of posts about Random numbers and random number generators. I’m here today to share a piece of code that we use very successful in our engine for fast and efficient random number generation. The source code is mainly thanks to Matthew Jackson who is collaborating with me in making the engine into a reality. Without further ado, here is the source, it is a 63 bit random number generator.
- Basic Feature List
~ ability to get and set the current seed
~ ability to get random numbers between min and max (long)
~ ability to get random numbers between min and max (float)
- Source
/**
* @author Matthew Jackson - Original Author
* @author David Arayan (DrHalfway) - Modifications to code
* @version 1.0 - Used as part of HalfWay Game Engine Math Library
*/
public class Random {
private long seed;
/**
* Default Constructor which generates the seed based on system time.
*/
public Random(){
seed = System.nanoTime();
}
/**
*
* @param seed The value to start the random number generator.
* A seed value of 0 generates a random seed based on system time
* which is the same as the default constructor.
*
*/
public Random(long seed){
if (seed == 0){
seed = System.nanoTime();
}
this.seed = seed;
}
/**
* Uses an XORShift to produce a 63 bit random number.
* Java's variables are all signed so the 64th bit is lost.
* Period is 2^64 - 1 (thanks Roquen)
* @return A pseudo-random 63 bit number
*/
private long rand() {
seed ^= (seed << 13);
seed ^= (seed >>> 7);
seed ^= (seed << 17);
//return Math.abs(seed - 1);
return seed;
}
/**
* Allows the user to assign a min and max value for the numbers
* they want returned.
* @param min Minimum value to be returned (Can be negative)
* @param max Maximum value to be returned (Can be negative)
* @return A long random value between min and max
*/
public long rand(long min, long max ){
if(min > max){
return rand(max,min);
}
if (min == max) {
return min;
}
return (rand() % (max + 1 - min)) + min;
}
/**
* A floating point random number generator.
*
* @param min The minimum floating point value
* @param max The maximum floating point value
* @param dev The number of decimal places you want returned.
* dev = 10 will return 1 decimal place.
* dev = 100 will return 2 decimal places.
* @return returns random floating point value between min and max.
*
*/
public float randf(float min, float max, int dev) {
if (min == max) {
return min;
}
return ((float)rand((int)(min * dev), (int)(max * dev))/dev);
}
/**
* Returns the current seed for the random number generator
*/
public long getSeed() {
return seed;
}
/**
* Sets the current seed to seed
*/
public void setSeed(final long seed) {
this.seed = seed;
}
}
Below is a simple test program
public class test {
public static void main(String[] args) {
Random rand = new Random();
final int guess = 42;
while (true) {
long guessed = rand.rand(1, 100);
System.out.println(guessed);
if (guessed == guess) {
break;
}
}
}
}
EDIT : Below I’ve included a small benchmark program for bench marking the run-times of the above Random generator Vs Java’s Random generator.
public class test {
public static void main(String[] args) {
Random xRandom = new Random();
java.util.Random jRandom = new java.util.Random();
final int runs = 1000;
long startTime = 0, stopTime = 0;
float xRun = 0.0f;
float jRun = 0.0f;
/*
* RUN THE JAVA RANDOM BENCHMARK
*/
startTime = System.nanoTime();
for (int i = 0; i < runs; i++) {
jRandom.nextInt(100);
}
stopTime = System.nanoTime();
jRun += ((stopTime - startTime) * 1e-6);
/*
* RUN THE XOR RANDOM BENCHMARK
*/
startTime = System.nanoTime();
for (int i = 0; i < runs; i++) {
xRandom.rand(0, 100);
}
stopTime = System.nanoTime();
xRun += ((stopTime - startTime) * 1e-6);
System.out.println("RunTime for JRandom: " + jRun + "ms For: " + runs + " runs");
System.out.println("RunTime for XRandom: " + xRun + "ms For: " + runs + " runs");
}
}
And Below are bench-marking results for different runs on my machine.
RunTime for JRandom: 0.283136ms For: 1000 runs
RunTime for XRandom: 0.236113ms For: 1000 runs
RunTime for JRandom: 3.022447ms For: 10,000 runs
RunTime for XRandom: 2.67428ms For: 10,000 runs
RunTime for JRandom: 11.892359ms For: 100,000 runs
RunTime for XRandom: 5.694059ms For: 100,000 runs
RunTime for JRandom: 23.15375ms For: 1,000,000 runs
RunTime for XRandom: 9.104691ms For: 1,000,000 runs
RunTime for JRandom: 120.58705ms For: 10,000,000 runs
RunTime for XRandom: 33.68179ms For: 10,000,000 runs
RunTime for JRandom: 1094.5873ms For: 100,000,000 runs
RunTime for XRandom: 289.4332ms For: 100,000,000 runs
Hope it helps you all for any game creation needs. All comments/contributions to the source are welcome!
EDIT2 - I’ve generated and added a bitmap image for comparison of “randomness” of this versus java’s random generator. Basically a pixel value is picked randomly in the range of 0 to 255. The images are 512 X 512 in size. Left is the above Generator, Right is Java’s Generator.
EDIT3 - Changed the rand() function as suggested by Roquen, cheers!
~DrHalfway