Will this:
new java.util.Random(/* random seed */ 0)
new java.util.Random(/* random seed */ 1)
result in somehow "less random" / "more similar" random generators than this?
new java.util.Random(/* random seed */ 0)
new java.util.Random(/* random seed */ 1000)
In other words: do I risk having similar series of ints obtained from the random generators if their random seeds are similar?
No, similar seeds, will not produce similar random numbers.
Only same seeds will produce same numbers.
The code to set the seed is:
void setSeed(long seed) {
this.seed = (seed ^ 0x5DEECE66DL) & ((1L << 48) - 1);
..}
This formula avoids that this.seed gets simlar values for the input seed value (used in the constructor, or by setSeed().
However there is some weakness, als explained in
http://dontpanic.42.nl/2011/03/when-random-isn-as-random-as-expected.html
The state updates used to produce pseudo-random numbers are chaotic. Hence, using adjacent seed values results in entirely different state trajectories.
Random numbers are never random. They are entirely pre-defined and given the same seed will always result in the same numbers even over a million different runs of the commands, that is the reason they are called "Pseudorandom". The best thing to do is to seed with a value that will be different each time the program is run and can not be predicted easily such as the current time and date and/or number of clock cycles that have passed.
Related
The Requirement:
I need to generate 4-digit non-duplicate number - even my application get closed, generation of number must not have to be duplicate.
I don't want to store all previous number in any storage.
Is there any algorithm which has highest possibility to produce most of unique number in a day ?
Thank you
Don't generate a random number. Instead, generate a sequential number from 0000 to 9999, and then obfuscate it using the technique described in https://stackoverflow.com/a/34420445/56778.
That way, the only thing you have to save is the next sequential number.
That example uses a multiplicative inverse to map the numbers from 0 to 100 to other numbers within the same range. Every number from 0 to 100 will be mapped to a unique number between 0 and 100. It's quick and easy, and you can change the mapping by changing the constants.
More information at http://blog.mischel.com/2017/06/20/how-to-generate-random-looking-keys/
Ten thousand is too few
Generating more than a few random numbers within a range of 0 to 9,999 is not likely to go well. Depending on how many such numbers you need, you are quite likely to run into duplicates. That seems rather obvious.
Cryptographically-strong random number generator
As for generating the most randomness, you need a cryptographically-strong random number generator that produces non-deterministic output.
java.security.SecureRandom
Java provides such a beast in the java.security.SecureRandom class. Study the class documentation for options.
SecureRandom secureRandom = new SecureRandom();
Notice that a SecureRandom is a java.util.Random. On that interface you will find convenient methods such as nextInt(int bound). You get a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive).
int r = secureRandom.nextInt( 10_000 ) ;
Let's try it.
SecureRandom secureRandom = new SecureRandom();
for( int i = 1 ; i <= 20 ; i ++ )
{
System.out.println( secureRandom.nextInt( 10_000 ) ) ;
}
7299
3581
7106
1195
8713
9517
6954
5558
6136
1623
7006
2910
5855
6273
1691
588
5629
7347
7123
6973
If you need more than few such numbers, or they absolutely must be distinct (no duplicates), than you must change your constraints.
For a small range like 10,000, keep a collection of generated numbers, checking each newly generated number to see if it has been used already.
Dramatically expand your limit far beyond 10,000.
UUID
If you need a universally unique identifier, use, well, a Universally Unique Identifier (UUID). Java represents a UUID value with the java.util.UUID class.
UUIDs were designed for systems to be able to independently generate a virtually unique identifier without coordinating with a central authority. They are 128-bit values. That is quadruple the 32-bits of a int integer primitive in Java. UUIDs are often displayed to humans as a canonically-formatted 36-character hexadecimal string grouped with hyphens. Do not confuse this textual representation for a UUID value itself; a UUID is a 128-bit value, not text.
The Version 1 type of UUIDs are ideal, as they represent a point in both space and time by combining a date-time, a MAC address, and a small arbitrary number. This makes it virtually impossible to have duplicates. By “virtually impossible”, I mean literally astronomically-large numbers. Java does not bundle a Version 1 generator because of security/privacy concerns. You can add a library, make a web services call, or ask your database such as Postgres to generate one for you.
Or, for most cases where we need a relatively small number of instances, use the Version 4 UUID where 122 of the 128 bits are randomly generated. Java bundles a Version 4 generator. Simply call UUID.randomUUID.
I agree with Basil Bourque and others about whether what you propose is the "right" approach. However, if you really want to do what you are proposing, then one way to achieve your goal (generate as many numbers as possible within range in pseudorandom order without having to store all previous values generated):
find a random number generator that has a period roughly within the range that you require;
to generate the next ID, take the next number generated, discarding ones that are not within range.
So for four digit numbers, one option would be an XORShift generator configured to generate 16 bit numbers (i.e. in the range 1-16383, near enough to 1-999):
private int seed = 1;
public int nextJobID() {
do {
seed = (seed ^ (seed << 5)) & 0x3fff;
seed = (seed ^ (seed >>> 3)) & 0x3fff;
seed = (seed ^ (seed << 7)) & 0x3fff;
} while (seed >= 10000);
return seed;
}
To generate a new sequence each "day", set 'seed' to any number between 1 and 16383. [It'll be the same sequence, just starting at a different point. You could vary the sequence a little e.g. by taking every nth job ID where n is a small number, reversing the pattern of shifts (do >>>, <<, >>> instead of <<, >>>, <<) or finding some other combination of shifts (not 5/3/7) that produce a complete period.]
This technique is guaranteed to produce all numbers in range in "random" order. It doesn't offer any other guarantee, e.g. that it will be the most efficient or produce the "highest quality" of randomness achievable. It's probably good enough -- if not as good as you can get -- given the requirements you set out.
If I pick a seed (say 999) and generate a stream of random numbers, how can I choose a second seed that ensures the second stream of random numbers does not match the first? Does the second seed need to be measurably different from 999? Would something as simple as seed2 = seed1 + 1000 work? The programming language I'm interested in is Java.
Simple question
java.lang.Math.random()
How does this work? Meaning there is no seed input, so does it generate a random number off the system time? Meaning like if two calls were made to this function at .00001s away from eachother (basically the same time), would it produce the same result?
Thanks!
The javadoc explains how it works:
When this method is first called, it creates a single new pseudorandom-number generator, exactly as if by the expression
new java.util.Random()
This new pseudorandom-number generator is used thereafter for all calls to this method and is used nowhere else.
Returned values are chosen pseudorandomly with (approximately) uniform distribution from that range. When this method is first called, it creates a single new pseudorandom-number generator, exactly as if by the expression new java.util.Random
This new pseudorandom-number generator is used thereafter for all calls to this method and is used nowhere else. This method is properly synchronized to allow correct use by more than one thread. However, if many threads need to generate pseudorandom numbers at a great rate, it may reduce contention for each thread to have its own pseudorandom-number generator.
In order to understand how does this code runs you must go through the various Random Number generator algorithms. In actual practice theres no concept call random numbers if you google "Psuedo Random Number Algorithm" then you can have a better insight about the various concepts.
Answering your Question : Yes there will be different if the Random Number Generator Algorithm is based on time (usually they are).
But at the output if u write
Random obj1 = new Random()
int p = obj1.nextInt(10%2)
int q = obj1.nextGaussian();
theres a chance that the same number may appear more than once. It is because the Number generated is undoubtedly a unique number but it due to various parameters the obtained output is filtered and so theres a probabilty that the ouput can be same
There are two principal means of generating random (really pseudo-random) numbers:
the Random class generates random integers, doubles, longs and so on, in various ranges.
the static method Math.random generates doubles between 0 (inclusive) and 1 (exclusive).
To generate random integers:
do not use Math.random (it produces doubles, not integers)
use the Random class to generate random integers between 0 and N.
To generate a series of random numbers as a unit, you need to use a single Random object - do not create a new Random object for each new random number.
Other alternatives are:
SecureRandom, a cryptographically strong subclass of Random
ThreadLocalRandom, intended for multi-threaded cases
import java.util.Random;
/** Generate 10 random integers in the range 0..99. */
public final class RandomInteger {
public static final void main(String... aArgs){
log("Generating 10 random integers in range 0..99.");
//note a single Random object is reused here
Random randomGenerator = new Random();
for (int idx = 1; idx <= 10; ++idx){
int randomInt = randomGenerator.nextInt(100);
log("Generated : " + randomInt);
}
log("Done.");
}
private static void log(String aMessage){
System.out.println(aMessage);
}
}
I can't understand what was the meaning of Seed in java.util.Random ? I had read Why does this code print “hello world”? question and I am still confuse about seed . Can anyone describe me kindfully what was seed actually mean ? Thanks.
In documentation for setSeed() method ... what does mean seed - the initial seed ?
public void setSeed(long seed)
Sets the seed of this random number generator using a single long seed. The general contract of setSeed is that it alters the state of this random number generator object so as to be in exactly the same state as if it had just been created with the argument seed as a seed. The method setSeed is implemented by class Random by atomically updating the seed to
(seed ^ 0x5DEECE66DL) & ((1L << 48) - 1)
and clearing the haveNextNextGaussian flag used by nextGaussian().
The implementation of setSeed by class Random happens to use only 48 bits of the given seed. In general, however, an overriding method may use all 64 bits of the long argument as a seed value.
Parameters:
seed - the initial seed
I would expect if I can understand exactly meaning of seed , I am sure I will understand clearly to this answer.
A pseudo-random number generator produces a sequence of numbers. It
isn't truly random, but generally a mathematical calculation which
produces an output that matches some desirable distribution, and
without obvious patterns. In order to produce such a sequence, there
must be state stored for the generator to be able to generate the next
number in that sequence. The state is updated each time using some
part of the output from the previous step.
Seeding explicitly initialises this state. A 'seed' is a starting
point, from which something grows. In this case, a sequence of
numbers.
This can be used either to always generate the same sequence (by using
a known constant seed), which is useful for having deterministic
behaviour. This is good for debugging, for some network applications,
cryptography, etc.
Or, in situations where you want the behaviour to be unpredictable
(always different each time you run a program, a card game perhaps),
you can seed with a number likely to be continually changing, such as
time.
The 'randomness' of the sequence does not depend on the seed chosen,
though it does depend on not reseeding the sequence.
Taken from What is a seed in relation to a random number generation algorithm and why is computer time used to create this seed more often than not?
This should answer your question.
The pseudorandom number generator is implemented in terms of an integer which is, each time you ask for a number, transformed into another integer by the pseudorandom sequence generator function.
The initial value of that internal integer is termed the seed. The idea is to set it differently each time you instantiate Random because the pseudorandom sequence is fully deterministic once the seed is assigned.
If you use the nullary constructor, new Random(), then System.currentTimeMillis() will be used for the seed, which is good enough for almost all cases.
java.util.Random.setSeed(long seed): Sets the seed of this random number generator using a single long seed
Syntax:
public void setSeed(long seed)
Parameters:
seed - the initial seed
Every Random constructed with the same seed will generate the same
pattern of numbers every time.
So basically we set seed with a long value when we want to get the
same random number sequence every time (like in video
games,debugging,etc)
I strongly recommend to go through this answer:https://stackoverflow.com/a/23127798/9080948
and this video:https://youtu.be/86_cnhqSyh0
For example if java produces the pseudorandom sequence: 9 3 2 5 6
by using 23 as a seed, how can I do the inverse? i.e. getting 23 out of the sequence 9 3 2 5 6.
Or how do I assign a seed for a certain sequence?
It is easy to do if there is a database - just assign a random key for the sequence
INSERT INTO SEQUENCE_TABLE VALUES (RANDOM_KEY, SEQUENCE)
However if I'm not permitted to use a database, Is there a formula to do such a thing?
Yes, it's absolutely easy to reverse engineer the number stream of a poorly designed pseudo random number generator, such as the Linear Congruential PRNG implementation in the Java programming language (java.util.Random).
In fact, with as few as TWO values from that particular generator, and the information on the order in which the values emerged, the entire stream can be predicted.
Random random = new Random();
long v1 = random.nextInt();
long v2 = random.nextInt();
for (int i = 0; i < 65536; i++) {
long seed = v1 * 65536 + i;
if (((seed * multiplier + addend) & mask) >>> 16) == v2) {
System.out.println("Seed found: " + seed);
break;
}
}
This is precisely why it's critical to use cryptographically secure random number generators that have been vetted by the community at large for implementations that require security.
There is much more information on reverse engineering PRNGs, including java.util.Random here. ...
The point of random number generators is that this is impossible. SecureRandom is designed to be especially cryptographically strong, but generally speaking, if you're writing a random number generator and this is possible or easy, you're doing it wrong.
That said, it's likely that it's not impossible with Java's built in Random class. (SecureRandom is another story, though.) But it will require staggering amounts of math.
To be more specific: if a polynomial-time algorithm existed to do what you want, for some particular pseudorandom number generator, then it would by definition fail the "next-bit test" described in the linked Wikipedia article, since you could predict the next elements that would be generated.
It is certainly possible to recover the seed used by java.util.Random. This post describes the math behind Random's linear congruential formula, and here is a function to discover the current seed from the last two integers returned from nextInt().
public static long getCurrentSeed(int i1, int i2) {
final long multiplier = 0x5DEECE66DL;
final long inv_mult = 0xDFE05BCB1365L;
final long increment = 0xBL;
final long mask = ((1L << 48) - 1);
long suffix = 0L;
long lastSeed;
long currSeed;
int lastInt;
for (long i=0; i < (1<<16); i++) {
suffix = i;
currSeed = ((long)i2 << 16) | suffix;
lastSeed = ((currSeed - increment) * inv_mult) & mask;
lastInt = (int)(lastSeed >>> 16);
if (lastInt == i1) {
/* We've found the current seed, need to roll back 2 seeds */
currSeed = lastSeed;
lastSeed = ((currSeed - increment) * inv_mult) & mask;
return lastSeed ^ multiplier;
}
}
/* Error, current seed not found */
System.err.println("current seed not found");
return 0;
}
This function returns a value that can be used with rand.setSeed() to generate a pseudorandom sequence of numbers starting with i1 and i2.
If you're OK with using a String as your seed, you can use this:
String seed = "9 3 2 5 6";
Then your generator would look like:
String[] numbers = seed.split(" ");
If you truly want to reverse engineer the "random" number generator in java, that's going to be quite difficult (I think).
It would be better to do it the other way around if you can: Start with a seed, produce the sequence, then work out from there.
You want to take arbitrary sequences of numbers, then determine a short (fixed length?) key which will allow you to regenerate that sequence of numbers, without storing the original? Unfortunately, what you want is technically impossible. Here's why:
This is a particular case of compression. You have a long sequence of data, which you want to be able to recreate losslessly from a smaller piece of information. If what you are requesting were possible, then I would be able to compress the whole of stack overflow into a single integer (since the entire website could be serialized into a sequence of numbers, albeit a very long one!)
Unfortunately, mathematics doesn't work that way. Any given sequence has a particular measure of entropy - the average amount of complexity in that sequence. In order to reproduce that sequence losslessly, you must be able to encode at least enough information to represent its entropy.
For certain sequences, there may in fact be a seed that is capable of generating a long, specific sequence, but that is only because there is a hard-coded mathematical function which takes that seed and produces a particular sequence of numbers. However, to take an arbitrary sequence of values and produce such a seed, you would need both a seed, and a function capable of producing that sequence from that seed. In order to encode both of these things, you'd find that you've got a lot more data than you'd expect!