How do I safely generate a random integer value in a specific range?
I know many people have asked this before, this post for example, but the method doesn't seem to be safe. Let me explain:
The 'Math' library has Math.random() which generates a random value in the range [0, 1). Using that, one can construct an algorithm like
int randomInteger = Math.floor(Math.random() * (Integer.MAX_VALUE - Integer.MIN_VALUE + 1) + Integer.MIN_VALUE)
to generate a random number between Integer.MAX_VALUE and Integer.MIN_VALUE. However, Integer.MAX_VALUE - Integer.MIN_VALUE will overflow.
The goal is not to merely generate random numbers but to generate them evenly, meaning 1 has the same probability to appear as Integer.MAX_VALUE. I know there are work-arounds to this, such as casting large values to long but then the problem again is how to generate a long integer value from Long.MIN_VALUE to Long.MAX_VALUE.
I'm also not sure about other pre-written algorithms as they can overflow too and cause the probability distribution to change. So my question is whether there is a mathematical equation that uses only integers (no casting to long anywhere) and Math.random() to generate random numbers from Integer.MIN_VALUE to Integer.MAX_VALUE. Or if anyone know any random generators that don't get overflow internally?
The 'Math' library have Math.random() which generates a random value in [0, 1) range.
So don't use Math.random() - use this:
Random r = new Random();
int i = r.nextInt();
The docs for nextInt say:
nextInt() - Returns the next pseudorandom, uniformly distributed int value from this random number generator's sequence. All 2^32 possible int values are produced with (approximately) equal probability.
It appears I misread the question slightly, and you need long not int - luckily the contract is the same.
long l = r.nextLong()
This will quite literally take two ints and jam them together to make a long.
Still better might be to use
java.security.SecureRandom which is a cryptographically strong random number generator (RNG).
Random x = new Random(1000); // code running and generate values 1000
int i = x.nextInt();
Related
I need a collection of 64-bit floating point random numbers, and they should be distinct. Is there a library routine for this, or should I manually search for duplicates?
It is actually more important to have the numbers not being closer than some very small constant \epsilon. Is there a library routine for that as well?
You may use streams for that.
double[] array = new Random().doubles()
.distinct()
.limit(500) // How many you want.
.toArray();
You can use Set collection. It won't allow insertion of unique values. Below is an example:
Set<Double> doubles = new HashSet<Double>();
Random r = new Random();
for(int i=0 ; i<100 ; i++){
doubles.add(r.nextDouble() * 100);
}
At first you need to understand, how a random-number-generator works. A sequence of positive integers, long integers, with no doubles in it, is calculated. This sequence is at least 2^31 elements long. The real doubles in the range of 0.0 ..... 1.0 are the result of a floating point division.Floating point division is never exact.
If you use this real numbers to generate integer in smaller interval, it is the quickest method,to use a random-number-generator, which gives you positive integer from that interval.
The algorithm for the Lehmer-generator is
x1 = (x0 * m) % div
x0 : the last random number,x1 the next random number. Div and m are prime numbers. m < div. The first x0 is select by the user.called seed number.
It is clear, that the x_i are smaller then div. For the other properties of good random-number-generator, there is no short proof.
My suggestion:
Write a method for a Lehmer-generator with m = 279470273 and div = 4294967291. I found these numbers on several web pages. Div = 2^32-5, so you can be sure to get a sequence of nearly 2^32 positive long integer,all different. Convert them to doubles and divide them with div as double. You get doubles in the open interval (0.0, ..... 1.0) and all these doubles are different.
The random integers are small enough, that the quotients are also different. If you use a random generator, which generate bigger integer random numbers, you can not sure, that doubles are also different, the reason are rounding errors.
I'm trying to get a random integer, but the way I'm doing it takes a really long time to get that random number ( like 10 seconds!)
Random generator=new Random();
do {
id=generator.nextInt();
}
while(id<=0||id>=4);
I'm trying to get a random number between (and include) 0 to 4
This code so far gets the job done, but 10 seconds is too long!
what is a better way to do this?
Thanks!
You want
generator.nextInt(5);
which returns a random integer between 0 and 4. The reason why your original code took so long was because it was generating random integers over and over, until it got one between 1 and 3.
Note that as you were throwing away everything 0 or less, and everything 4 or more, you weren't even getting the range that you expected.
More information on the methods of the Random class can be found at http://docs.oracle.com/javase/7/docs/api/java/util/Random.html
That's because you're generating literally probably billions of random numbers and throwing them away until you get one between 0 and 4. Instead:
id = generator.nextInt(5); // number between 0 and 4, inclusive
In the future, please read the documentation for the classes you're using; this is clearly explained in the Javadoc.
Use Math.random() cast it into int
int i=(int)Math.random()*4;
Just include the upper bound (assuming you want 1, 2, or 3):
id = 1 + generator.nextInt(3);
From the javadoc:
public int nextInt(int n)
Returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive), drawn from this random number generator's sequence.
try this:
Random random = new Random();
random.nextInt(4);
I was curious to know why random_number=a+rand()%b; in C produces a random number between a and b (non-inclusive of b). But in Java this code will not work. I understand that the correct way to do this in Java is random_number=a+(Math.random()*(b-a)); but I was curious to know why there is a difference? Isn't it the same operation mathematically? I also understand that the return types are different for the random functions, but how does this difference explain the difference in output? Sorry if this seems like a trivial question but I was curious nonetheless.
The difference lies in what each random generator does.
In Java, Math.Random returns a pseudo-random number of the range 0 (inclusive) through 1 (exclusive). So it must be scaled up by b - a, the width of the range, then shifted by a, the start of the range.
In C, rand() returns numbers in the range 0 to RAND_MAX (my RAND_MAX is 32767), so %b is used to control the width of the range, and the start of the range is shifted by a.
One can, of course use java.util.Random's nextInt() or nextInt(int n) method to more exactly mimic the C scheme. nextInt() is almost exactly the same as rand() (though hopefully better distributed) while nextInt(int n) effectively subsumes the %n calculation.
In java it is nextInt()
int nextInt(int n)
This function returns random number between 0 to n
In C it is rand()
int rand(void)
This function returns an integer value between 0 and RAND_MAX.
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!
After I imported the math class...
Math.random()
I am confused at how to make the range of the numbers. I know you can multiply, and then add/subtract, but the logic is not making sense to me, and I am also not overly sure how to make the range. Can I get some help?
If you want the range [min, max], then you can use this formula:
Math.random() * (max - min) + min
random()
Returns a double value with a positive sign, greater than or equal to 0.0 and less than 1.0.
Make your own arrangement like if you need it below 50 multiply it by 50.
If you're trying to get a range of integers from 0 to n, then look at java.util.Random nextInt(int n)
Math.random() returns a double in between 0 and 1. So, say you wanted a number between 0 and 10:
double random = Math.random()*10;
Or maybe a range from -10 to 10:
double random = (Math.random()-0.5)*20;
Notice how I did *20 instead of 10. Subtracting 0.5 would then return a value between -0.5 and 0.5, so 0.5*20 = 10 and -0.5*20 = -10.
You have to describe you problem more. Anyway, in Java, there is class which is created specifically for working with Random numbers. Which is java.util.Random. Refer java documentation for more details. It has many methods which helps you to work with random numbers in many ways.
Some of the methods are nextInt(int limit) will give a random value between zero(inclusive) and limit(exclusive). If you need real numbers, then you have nextDouble() which will give a value between 0.0 and 1.0.