math.random() follows which algorithms - java

Am using math.random() method to generate random numbers. but i had a doubt about that method. math.random() is which algorithms will fallow to generate random numbers. Is there any another random number generated algorithm?
Am trying this code but i think this is not efficient to generate random code:
for (int i = 0; i < N; i++) {
int sd = i + (int) (Math.random() * (N-i));
String t = one[r];
one[r] = one[i];
one[i] = t;
}
Is there any better algorithm for random number generation?

Java mainly provides four random number generator API's depending of your use case.
java.lang.Math.random()
If we check the Math class source code, we can view this:
private static Random randomNumberGenerator;
private static synchronized void initRNG() {
if (randomNumberGenerator == null)
randomNumberGenerator = new Random();
}
public static double random() {
if (randomNumberGenerator == null) initRNG();
return randomNumberGenerator.nextDouble();
}
Math.random() is simply a shortcut to call Random Class. It is more simple and less complete than java.util.Random but it's enough in some cases.
java.util.Random
The Random class implement a Linear Congruential Generator.
LCG is a pretty simple formula for Pseudorandom Number Generation. java.util.Random is not trully random, it is totally deterministric. With the same initial condition (also called the seed), you've got the same result in the same order.
Use java.util.Random is good for the most use cases (simulation, games, ...) but is not good for cryptography because of his predictability, for this kind of use case prefer java.security.SecureRandom.
java.util.Random is thread safe but can have performance issues in multi-threaded context. If you work in a multi-threaded application, prefer ThreadLocalRandom.
java.security.SecureRandom
The SecureRandom class extend java.util.Random class to implement a cryptographically strong random number generator based on an entropy source. SecureRandom is not deterministic.
SecureRandom have multiple implementation in function of your platform (the complete implementation list).
java.security.SecureRandom is less fast than java.util.Random because of entropy source.
java.util.concurrent.ThreadLocalRandom
The ThreadLocalRandom class is another implementation of Linear Congruential Generator but this one isn't thread-safe but dedicated to a specific thread.
This implementation is more fast than java.util.Random in multi-threaded context.
In your case, you could use java.util.Collections.shuffle(list) to shuffle your array with java.util.Random or with a specific Random Generator like java.security.SecureRandom.

Use java.util.Random API
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.)
Algorithm class : pseudorandom number generator known as PRNG. You can read more about it here.
Note : Math.random() also uses java.util.Random instance to generate the psuedo-random numbers internally

It uses the pseudo random number generation algorithms ie the numbers which are constantly fluctuating from throughout the system.
You may also find this interseting to read:- Pseudo-Random vs. True Random
Also check the Source for java.util.Random

The simplest way to do what you are trying to do is
String[] words = ...
Collections.shuffle(Arrays.asList(words));
You are right that generating a random double and then turning it into a small integer is not efficient. Fortunately Random has a method for this.
Random rand = new Random();
for (int i = words.length - 1; i > 0; i--) {
int sd = rand.nextInt(i+1); // random number between 0 and i inclusive
String t = words[r];
words[r] = words[i];
words[i] = t;
}

Here are 2 methods to Shuffle an Array:
Approach 1: Shuffle elements in an array
Approach 2: Java Collection.shuffle() method
And the method you use is one standard way accomplishing this.
There are 2 ways in java: java.util.Random and java.lang.Math.random.
java.lang.Math.random() uses java.util.Random.
It provides only doubles and has no seeding capability.

Related

Create random BigInteger using RandomGenerator (introduced in Java 17)

The class BigInteger provides the constructor
public BigInteger(int numBits, Random rnd)
Since Java 17 the use of RandomGenerator is encouraged. How can I generate a random BigInteger in the range 0...(2^n)-1 using only an instance of RandomGenerator.
Just using Random & SecureRandom
Why do you need this? Because the new Random() gets you a relatively fast non-secure random number generator and new SecureRandom() provides a CSPRNG (Cryptographically Secure Pseudo Random Number Generator). Both those instances are instances of the RandomGenerator interface. So the only time you'd need this is if you want a specific Random generator defined in the random package.
If you don't need speed and you haven't any specific needs regarding the distribution - you'd probably know if you'd have any - then please just use new BigInteger(n, new SecureRandom()).
Implementing Random
TL;DR: don't
As RandomGenerator is an interface. The Random class has been refactored into a class that implements the interface. That means you can use the old Random wherever an interface specifies RandomGenerator. However, that doesn't work the other way around.
Random itself is not a final class, so it can be inherited from. So you could, in principle, create an adapter class by simply implementing all methods in Random and calling the similarly named methods of a wrapped RandomGenerator. This is however very dangerous practice as future extensions of Random may break everything. In the worst case it will show inconsistent behavior by mixing the state of the parent Random object and the wrapped RandomGenerator.
Move to Java 19
In Java 19 (build b21) there is an adapter method provided for RandomGenerator named Random#from(RandomGenerator). You can see the feature request here. Note that this is an intermediate step; preferably the BigInteger method should be retrofitted to use RandomGenerator (as stated in the feature request).
Beware that you should never use this wrapper class if you suspect that setSeed can ever be called, e.g. when generating a large prime in the BigInteger class. If it is called it will generate an UnsupportedOperationException.
These kind of classes go through all kinds of testing so the Java provided method can be trusted. However, the fact that a method can be retrofitted to use setSeed could be a problem regarding forward compatibility - you have been warned.
The special case of [0, n^2)
However, you've got one out: the range 0..2^n-1 or [0, 2^n-1) is a number consisting of a set of bits. So what you can do is use your RandomGenerator, fill an array of bytes, remove the most significant bits from the first byte (as Java is big endian), and then convert the array into a signed integer:
/**
* Mimics the {#link BigInteger#BigInteger(int, Random)} function using a
* {#link RandomGenerator} instance.
*
* #param numBits maximum bitLength of the new BigInteger.
* #param rnd source of randomness to be used in computing the new
* BigInteger.
* #throws IllegalArgumentException {#code numBits} is negative.
* #see #bitLength()
*/
public static BigInteger generateRandomBigInteger(int numBits, RandomGenerator rng) {
if (numBits < 0) {
throw new IllegalArgumentException("numBits must be non-negative");
}
if (numBits == 0) {
return BigInteger.ZERO;
}
int bytes = (numBits + Byte.SIZE - 1) / Byte.SIZE;
// mask bits that we need the value of to 1, the others - if any -- will be set
// to zero
byte bitMask = (byte) ((1 << ((numBits - 1) % Byte.SIZE + 1)) - 1);
byte[] randomBytes = new byte[bytes];
rng.nextBytes(randomBytes);
randomBytes[0] &= bitMask;
return new BigInteger(1, randomBytes);
}
numBits is of course the same as your n variable.
The case for [0, max)
Actually, you can combine the comparison function and the random bit generator in such a way that you can create large random values in the range 0..max with max having any value, with a minimum amount of random bits and no nasty BigInteger operations (such as division) at all.
You can find my implementation of that here but you may get weirded out. Sorry in advance, and yes, this is a shameless plug of my RNGBC algorithm :)

Unique random - srand in java ? (like in c++)

Currently I'm using a
Random rand = new Random();
myNumber = rand.nextInt((100-0)+1)+0;
and it's a pseudo-random, because I always get the same sequence of numbers.
I remember in c++ you could just use the ctime and use srand to make it unique. How do you do it in java ?
If you require a unique random in Java, use SecureRandom. This class provides a cryptographically strong random number generator (RNG), meaning it can be used when creating certificates and this class is slow compared to the other solutions.
If you require a predictable random that you can reset, use a Random, where you call .setSeed(number) to seed it to make the values predictable from that point.
If you want a pseudo-random that is random every time you start the program, use a normal Random. A random instance is seed by default by some hash of the current time.
For the best randomness in every solution, it is important to RE-USE the random instance. If this isn't done, most of the output it gives will be similar over the same timespan, and at the case of a thrown away SecureRandom, it will spend a lot of time recreating the new random.

What is random seed about?

For example the code below. It has a random class. However it always produce the same output everywhere . In this case which item is the seed?
source: link
import java.util.Random;
public class RandomTest {
public static void main(String[] s) {
Random rnd1 = new Random(42);
Random rnd2 = new Random(42);
System.out.println(rnd1.nextInt(100)+" - "+rnd2.nextInt(100));
System.out.println(rnd1.nextInt()+" - "+rnd2.nextInt());
System.out.println(rnd1.nextDouble()+" - "+rnd2.nextDouble());
System.out.println(rnd1.nextLong()+" - "+rnd2.nextLong());
}
}
42 is the seed, as the very same Javadoc says. So, what is a seed? A random number is seldom truly random - often it's a pseudo-random instead. This means it's generated from a function, which is said PRNG (pseudo random number genrator). Being generated from a function, in turn, means that the output is not random anymore, since it's predictable!
However, depending on your needs, this pseudo-randomness may be enough - I said enough because generating random bit is expensive, and I'm not talking about time or memory, but about money (see this link on wikipedia). So, for example, if you need a random value to place enemies in your game, a pseudo-random number is ok - but if your are building security-related software, you want to use a true random number, or at least a cryptographically secure PRNG.
How can we describe a PRNG, like the one used in Math.random()? It's a function, initialized with a seed S that returns an array of values A. Note that, for each integer S, is defined one and only one array A. For example (values are not actual):
first call second call third call
seed: 14329 .18 .82 .5
seed: 3989 .7 .02 .93
So you seed you PRNG with some known value when you want its result to be predictable - for example for testing purposes or to ensure that, each time you run level 1 in your game, the enemies are always placed in the same (pseudo) random places - otherwise you don't need to explicitely pass a seed.
Random Seed on Wikipedia:
A random seed (or seed state, or just seed) is a number (or vector)
used to initialize a pseudorandom number generator.
In other word, it is the number from which a seem-to-be-random sequence will be generated. Therefore, if you use the same number, the senquence will always be the same.
In practice, we usually use System Time as seed.
The seed is given as the argument of the constructor of Random; using the same seed will yield the same sequence of numbers. However this is discussed under the link in thet question.
In this case the seed is 42. This is the reason for the same output - you use the same seed.
You can use for example
Random rnd1 = new Random(System.currentTimeMillis())
for different outputs.
The seed is the initial value of the internal state of the pseudorandom number generator which is maintained by method next(int).
The invocation new Random(seed) is equivalent to:
Random rnd = new Random();
rnd.setSeed(seed);
From the Java documentation in the Random class
Creates a new random number generator using a single long seed. The seed is the initial value of the internal state of the pseudorandom number generator which is maintained by method next(int).
The invocation new Random(seed) is equivalent to:
Random rnd = new Random();
rnd.setSeed(seed);
So 42 is the seed given to the new Random() in your example

Random.nextInt(int) is [slightly] biased

Namely, it will never generate more than 16 even numbers in a row with some specific upperBound parameters:
Random random = new Random();
int c = 0;
int max = 17;
int upperBound = 18;
while (c <= max) {
int nextInt = random.nextInt(upperBound);
boolean even = nextInt % 2 == 0;
if (even) {
c++;
} else {
c = 0;
}
}
In this example the code will loop forever, while when upperBound is, for example, 16, it terminates quickly.
What can be the reason of this behavior? There are some notes in the method's javadoc, but I failed to understand them.
UPD1: The code seems to terminate with odd upper bounds, but may stuck with even ones
UPD2:
I modified the code to capture the statistics of c as suggested in the comments:
Random random = new Random();
int c = 0;
long trials = 1 << 58;
int max = 20;
int[] stat = new int[max + 1];
while (trials > 0) {
while (c <= max && trials > 0) {
int nextInt = random.nextInt(18);
boolean even = nextInt % 2 == 0;
if (even) {
c++;
} else {
stat[c] = stat[c] + 1;
c = 0;
}
trials--;
}
}
System.out.println(Arrays.toString(stat));
Now it tries to reach 20 evens in the row - to get better statistics, and the upperBound is still 18.
The results turned out to be more than surprising:
[16776448, 8386560, 4195328, 2104576, 1044736,
518144, 264704, 132096, 68864, 29952, 15104,
12032, 1792, 3072, 256, 512, 0, 256, 0, 0]
At first it decreases as expected by the factor of 2, but note the last line! Here it goes crazy and the captured statistics seem to be completely weird.
Here is a bar plot in log scale:
How c gets the value 17 256 times is yet another mystery
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.
The implementation of Random uses a simple linear congruential formula. Such formulae have a natural periodicity and all sorts of non-random patterns in the sequence they generate.
What you are seeing is an artefact of one of these patterns ... nothing deliberate. It is not an example of bias. Rather it is an example of auto-correlation.
If you need better (more "random") numbers, then you need to use SecureRandom rather than Random.
And the answer to "why was it implemented that way is" ... performance. A call to Random.nextInt can be completed in tens or hundreds of clock cycles. A call to SecureRandom is likely to be at least 2 orders of magnitude slower, possibly more.
For portability, Java specifies that implementations must use the inferior LCG method for java.util.Random. This method is completely unacceptable for any serious use of random numbers like complex simulations or Monte Carlo methods. Use an add-on library with a better PRNG algorithm, like Marsaglia's MWC or KISS. Mersenne Twister and Lagged Fibonacci Generators are often OK as well.
I'm sure there are Java libraries for these algorithms. I have a C library with Java bindings if that will work for you: ojrandlib.

Uniform distribution with Random

I know if i use the Random generator from Java, generating numbers with nextInt, the numbers will be uniformly distributed. But what happens if I use 2 instances of Random, generating numbers with the both Random classes. The numbers will be uniformly distributed or not?
The numbers generated by each Random instance will be uniformly distributed, so if you combine the sequences of random numbers generated by both Random instances, they should be uniformly distributed too.
Note that even if the resulting distribution is uniform, you might want to pay attention to the seeds to avoid correlation between the output of the two generators. If you use the default no-arg constructor, the seeds should already be different. From the source code of java.util.Random:
private static volatile long seedUniquifier = 8682522807148012L;
public Random() { this(++seedUniquifier + System.nanoTime()); }
If you are setting the seed explicitly (by using the Random(long seed) constructor, or calling setSeed(long seed)), you'll need to take care of this yourself. One possible approach is to use a random number generator to produce the seeds for all other generators.
Well, if you seed both Random instances with the same value, you will definitely not get quality discrete uniform distribution. Consider the most basic case, which literally prints the exact same number twice (doesn't get much less random than that ...):
public class RngTest2 {
public static void main(String[] args) throws Exception {
long currentTime = System.currentTimeMillis();
Random r1 = new Random(currentTime);
Random r2 = new Random(currentTime);
System.out.println(r1.nextInt());
System.out.println(r2.nextInt());
}
}
But that's just a single iteration. What happens if we start cranking up the sample size?
Here is a scatter plot of a distribution from running two same-seeded RNGs side-by-side to generate 2000 numbers total:
And here is a distribution of running a single RNG to generate 2000 numbers total:
It seems pretty clear which approach produced higher quality discrete uniform distribution over this finite set.
Now almost everyone knows that seeding two RNGs with the same seed is a bad idea if you're looking for high quality randomness. But this case does make you stop and think: we have created a scenario where each RNG is independently emitting fairly high quality randomness, but when their output is combined it is notably lower in quality (less discrete.)

Categories