I made a class called QuickRandom, and its job is to produce random numbers quickly. It’s really simple: just take the old value, multiply by a double, and take the decimal part.
Here is my QuickRandom class in its entirety:
public class QuickRandom {
private double prevNum;
private double magicNumber;
public QuickRandom(double seed1, double seed2) {
if (seed1 >= 1 || seed1 < 0) throw new IllegalArgumentException("Seed 1 must be >= 0 and < 1, not " + seed1);
prevNum = seed1;
if (seed2 <= 1 || seed2 > 10) throw new IllegalArgumentException("Seed 2 must be > 1 and <= 10, not " + seed2);
magicNumber = seed2;
}
public QuickRandom() {
this(Math.random(), Math.random() * 10);
}
public double random() {
return prevNum = (prevNum*magicNumber)%1;
}
}
And here is the code I wrote to test it:
public static void main(String[] args) {
QuickRandom qr = new QuickRandom();
/*for (int i = 0; i < 20; i ++) {
System.out.println(qr.random());
}*/
//Warm up
for (int i = 0; i < 10000000; i ++) {
Math.random();
qr.random();
System.nanoTime();
}
long oldTime;
oldTime = System.nanoTime();
for (int i = 0; i < 100000000; i ++) {
Math.random();
}
System.out.println(System.nanoTime() - oldTime);
oldTime = System.nanoTime();
for (int i = 0; i < 100000000; i ++) {
qr.random();
}
System.out.println(System.nanoTime() - oldTime);
}
It is a very simple algorithm that simply multiplies the previous double by a “magic number” double. I threw it together pretty quickly, so I could probably make it better, but strangely, it seems to be working fine.
This is sample output of the commented-out lines in the main method:
0.612201846732229
0.5823974655091941
0.31062451498865684
0.8324473610354004
0.5907187526770246
0.38650264675748947
0.5243464344127049
0.7812828761272188
0.12417247811074805
0.1322738256858378
0.20614642573072284
0.8797579436677381
0.022122999476108518
0.2017298328387873
0.8394849894162446
0.6548917685640614
0.971667953190428
0.8602096647696964
0.8438709031160894
0.694884972852229
Hm. Pretty random. In fact, that would work for a random number generator in a game.
Here is sample output of the non-commented out part:
5456313909
1427223941
Wow! It performs almost 4 times faster than Math.random.
I remember reading somewhere that Math.random used System.nanoTime() and tons of crazy modulus and division stuff. Is that really necessary? My algorithm performs a lot faster and it seems pretty random.
I have two questions:
- Is my algorithm “good enough” (for, say, a game, where really random numbers aren’t too important)?
- Why does
Math.randomdo so much when it seems just simple multiplication and cutting out the decimal will suffice?
Your
QuickRandomimplementation hasn’t really an uniform distribution. The frequencies are generally higher at the lower values whileMath.random()has a more uniform distribution. Here’s a SSCCE which shows that:The average result looks like this:
If you repeat the test, you’ll see that the QR distribution varies heavily, depending on the initial seeds, while the MR distribution is stable. Sometimes it reaches the desired uniform distribution, but more than often it doesn’t. Here’s one of the more extreme examples, it’s even beyond the borders of the graph: