Math.Random() Versus Random.Nextint(Int)

Math.random() versus Random.nextInt(int)

Here is the detailed explanation of why "Random.nextInt(n) is both more efficient and less biased than Math.random() * n" from the Sun forums post that Gili linked to:

Math.random() uses Random.nextDouble() internally.

Random.nextDouble() uses Random.next() twice to generate a double that has approximately uniformly distributed bits in its mantissa, so it is uniformly distributed in the range 0 to 1-(2^-53).

Random.nextInt(n) uses Random.next() less than twice on average- it uses it once, and if the value obtained is above the highest multiple of n below MAX_INT it tries again, otherwise is returns the value modulo n (this prevents the values above the highest multiple of n below MAX_INT skewing the distribution), so returning a value which is uniformly distributed in the range 0 to n-1.

Prior to scaling by 6, the output of Math.random() is one of 2^53 possible values drawn from a uniform distribution.

Scaling by 6 doesn't alter the number of possible values, and casting to an int then forces these values into one of six 'buckets' (0, 1, 2, 3, 4, 5), each bucket corresponding to ranges encompassing either 1501199875790165 or 1501199875790166 of the possible values (as 6 is not a disvisor of 2^53). This means that for a sufficient number of dice rolls (or a die with a sufficiently large number of sides), the die will show itself to be biased towards the larger buckets.

You will be waiting a very long time rolling dice for this effect to show up.

Math.random() also requires about twice the processing and is subject to synchronization.

Math.random() v/s Random class

If you look at the implementation of Math.random(), you'll see that it uses an instance of the Random class :

public static double random() {
return RandomNumberGeneratorHolder.randomNumberGenerator.nextDouble();
}

private static final class RandomNumberGeneratorHolder {
static final Random randomNumberGenerator = new Random();
}

Therefore the randomness would be the same.

That said, since you need an int and not a double, you'd better use the nextInt method of the Random class, since it would save you the multiplication and casting of a double to int.

Random rnd = new Random();
int num = rnd.nextInt(41)+30;

Why is Random.nextInt() and Math.random going out of the range I set?

Think about this part:

random.nextInt(75) + 25

You're generating a number between 0 and 74, then adding 25. This generates a random number from 25 to 99. If it generates 74 and you add 25, it becomes 99.

You need to subtract the lower bound before generating:

random.nextInt(75 - 25) + 25)

Java Math.abs random vs. nextInt()


Math.abs(rand.nextInt()) % 8 + 1;

This has a subtle bug. Math.abs(Integer.MIN_VALUE) returns MIN_VALUE which is a negative number. A simpler solution is

(rand.nextInt() & 7) + 1;

This will always be non-negative and be slightly faster.

rand.nextInt(8) + 1

This is both faster, but more importantly, clearer as to what you are trying to achieve. For the later reason, rather than speed alone, it is the better choice.

Note: You could use abs if you really wanted to like this. However this is not as clean as the nextInt call.

Math.abs(rand.nextInt() % 8) + 1;

how random is Math.random() in java across different jvms or different machines

Math.random() is based on java.util.Random, which is based on a linear congruential generator. That means its randomness is not perfect, but good enough for most tasks, and it sounds like it should be sufficient for your task.

However, it sounds like you're using the double return value of Math.random() to choose between a fixed number of choices, which may further degrade the quality of the randomness. It would be better to use java.util.Random.nextInt() - just be sure to reuse the same Random object.

Sometimes, it doesn't appear so random by looking at a snapshot on a resource pool to see which pieces it's getting at that instant

Our brains are really good at spotting patterns in perfect randomness, so that means almost nothing.

Random.nextInt(int) is [slightly] biased

http://docs.oracle.com/javase/6/docs/api/java/util/Random.html:

An instance of this class is used to generate a stream of
pseudorandom numbers. The class uses a 48-bit seed, which is modified
using a linear congruential formula. (See Donald Knuth, The Art of
Computer Programming, Volume 3, Section 3.2.1.)

If two instances of Random are created with the same seed, and the
same sequence of method calls is made for each, they will generate and
return identical sequences of numbers. [...]

It is a pseudo-random number generator. This means that you are not actually rolling a dice but rather use a formula to calculate the next "random" value based on the current random value. To creat the illusion of randomisation a seed is used. The seed is the first value used with the formula to generate the random value.

Apparently javas random implementation (the "formula"), does not generate more than 16 even numbers in a row.

This behaviour is the reason why the seed is usually initialized with the time. Deepending on when you start your program you will get different results.

The benefits of this approach are that you can generate repeatable results. If you have a game generating "random" maps, you can remember the seed to regenerate the same map if you want to play it again, for instance.

For true random numbers some operating systems provide special devices that generate "randomness" from external events like mousemovements or network traffic. However i do not know how to tap into those with java.

From the Java doc for secureRandom:

Many SecureRandom implementations are in the form of a pseudo-random
number generator (PRNG), which means they use a deterministic
algorithm to produce a pseudo-random sequence from a true random seed.
Other implementations may produce true random numbers, and yet others
may use a combination of both techniques.

Note that secureRandom does NOT guarantee true random numbers either.

Why changing the seed does not help

Lets assume random numbers would only have the range 0-7.
Now we use the following formula to generate the next "random" number:

 next = (current + 3) % 8

the sequence becomes 0 3 6 1 4 7 2 5.

If you now take the seed 3 all you do is to change the starting point.

In this simple implementation that only uses the previous value, every value may occur only once before the sequence wraps arround and starts again. Otherwise there would be an unreachable part.

E.g. imagine the sequence 0 3 6 1 3 4 7 2 5. The numbers 0,4,7,2 and 5 would never be generated more than once(deepending on the seed they might be generated never), since once the sequence loops 3,6,1,3,6,1,... .

Simplified pseudo random number generators can be thought of a permutation of all numbers in the range and you use the seed as a starting point. If they are more advanced you would have to replace the permutation with a list in which the same numbers might occur multiple times.

More complex generators can have an internal state, allowing the same number to occur several times in the sequence, since the state lets the generator know where to continue.

math.random always give 0 result

Math.random() returns a double value between 0 (inclusive) and 1 (exclusive). It does not return an integer value. Therefore, when you take the number produced by Math.random() modulo 10, it returns the same double value. The final cast to int makes that value always 0.

Run the following code to see for yourself:

double random = Math.random();
System.out.println(random); // for example 0.5486395326203879
System.out.println(random % 10); // still 0.5486395326203879
System.out.println((int) (random % 10)); // outputs 0

What you really want is to use a Random object and use Random.nextInt(bound). To have a random integer between 0 and 9, you can use:

Random random = new Random();
int value = random.nextInt(10);


Related Topics



Leave a reply



Submit