How to scale pseudo random numbers to a specific range? - java

How would I scale random numbers to say 1-10
whithout loosing the randomness?
I know, just using % 10 is not a good idea.
And in addition, I need a seed value, so I can test on
determinsitic numbers,
but I have not understood what value this seed should have
and I how it influences the sequence.
Is there a difference if it is high or low ?
thanks in advance.

import java.util.Random;
Random random = new Random( yourSeed );
int randomInt = random.nextInt(10) + 1 ;
The seed has no other purpose than to give the PRNG a starting point. It is purely arbitrary and will not influence the distribution of the random numbers.
The nextGaussian() is different in that it returns floating point numbers distributed around a bell curve.

usually when trying to get a random value you'll use something like this:
public int getRandom( int min, int max )
{
return (int) Math.round( Math.random() % (max - min) + min );
}
Or, as I just remembered from Stavr00's answer, use one of the built in functions from java.util.Random

Related

How do you generate a random decimal with decimals above 0 in Java?

I need to generate a random decimal from 0.85 to 1. I saw on other questions a lot of different methods, but all of them count on the beginning number to be 0. How do I do this?
Well, Math.random() will generate a number from 0 to 1, so Math.random()/100 will generate a number from 0 to 0.01, so Math.random()/100*15 will generate a number from 0 to 0.15, so Math.random()/100*15 + 0.85 will generate a number from 0.85 to 1
Another way to think of it:
double min = 0.85;
double max = 1.0;
double value = Math.random() * (max - min) + min;
If you want numbers between 0.85 and 1, inclusive, use SplittableRandom and its nextDouble(double origin, double bound) method, or use ThreadLocalRandom and its nextDouble(double origin, double bound) method.
Since the upper bound is exclusive in those methods, you need to bump up the double value by the smallest amount possible, which you can do by calling Math.nextUp(double d).
// Use one of these:
SplittableRandom rnd = new SplittableRandom();
ThreadLocalRandom rnd = ThreadLocalRandom.current();
// Then generate random values like this:
double value = rnd.nextDouble(0.85, Math.nextUp(1d));
For the purpose of providing an alternative, if random has type Random then a single double in the range .85 (inclusive) to 1 (exclusive) would be:
random.doubles(0.85, 1.00).findFirst().getAsDouble();
This is more useful if you wish to generate several values within the range.
Note that an advantage of Random over Math.random is that you can provide a seed which is useful for testing.

Formula to make higher numbers harder to get in a random

I'm looking for a formula or a method to allow getting higher numbers in a random harder to obtain. For instance if I was attempting to get a number out of 1000, getting 1000 would be much harder than getting a lower number such as 1 - 250.
One easy way is to use square roots, which make it easier to get higher numbers. We then subtract from 1,000 to make it easier to get lower numbers instead.
If the lowest value you want is zero:
1000 - (int) Math.sqrt(rand.nextInt(1001*1001))
If the lowest value you want is one:
1000 - (int) Math.sqrt(rand.nextInt(1000*1000))
Well, POisson distribution with lambda less than or equal to 1 would fit your requirements
public static int getPoisson(double lambda) {
double L = Math.exp(-lambda);
double p = 1.0;
int k = 0;
do {
k++;
p *= Math.random();
} while (p > L);
return k - 1;
}
call it with 1 and see if it is what you want
Use a Rand for the high number, as in
highNum = Rand(1,4) *250;
randNum = Rand(1, highNum);
Using this formula, numbers between 1-250 have 8.3 times chance over numbers between 750-1000

How can I optimize generating random numbers between 0 and 133300 until a defined target is reached?

import java.util.Random;
public class FindInt{
public static void main(String[] args){
int guess = 49;
int trys = 0;
Random r = new Random();
while(r.nextInt(133300) != guess){
trys = trys + 1;
}
System.out.println(guess + " has been found in random after " + trys + " trys!");
}
}
Is there a more efficient way to write this, or is my usage of a while loop correct? Any additional suggestions to optimize this code would be appreciated.
Assuming we can trust Random() class (yes generating Random numbers can be tricky)
to generate random numbers.
your probability of guessing the number on every try is 1/133000
now let's say you can only guess up to 10 numbers, then the probability of guessing that number goes up to (1/13300)*10.
Since there is always a chance of Random class returns the same number twice, then we can make the algorithm slightly more clever and refine the algorithm to say only guess a number once.
this will increase the probability to (1/13300)+(1/13299)+...+(1/13291)
Obviously storing the previous generated numbers can use more memory. so you have to give up memory for speeding up the process.
Yes your usage of the while loop is correct.
#EricLang you're trying to guess number49. The random function you are calling:
public int nextInt(int n)
Returns a pseudorandom, uniformly distributed int value between 0 (inclusive) and the specified value (exclusive).
In your case n is equal to 133300, if you decrease that number you increase your probability to find it sooner. If you call it with 50 instead of 133300 it's very likely to be guessed with less tries.
But all this depends on your requirements.

Random number array with lazy initialization

For a distributed application project I want to have two instances share the same/know (pseudo-)random numbers.
This can be achieved by using the same seed for the random number generator (RNG). But this only works if both applications use the RNG output in the same order. In my case this is hard or even impossible.
Another way of doing this is would be (psedocode):
rng.setSeed(42);
int[] rndArray;
for(...) {
rndArray[i] = rng.nextInt();
}
Now both applications would have the same array of random numbers and my problem would be solved.
BUT the array would have to be large, very large. This is where the lazy initialization part comes in: How can I write a class that where rndArray.get(i) is always the same random number (depending on the seed) without generating all values between 0 and i-1?
I am using JAVA or C++, but this problem should be solvable in most programming languages.
You can use a formula based on a random seed.
e.g.
public static int generate(long seed, int index) {
Random rand = new Random(seed + index * SOME_PRIME);
return rand.nextInt();
}
This will produce the same value for a given seed and index combination. Don't expect it to be very fast however. Another approach is to use a formula like.
public static int generate(long seed, int index) {
double num = seed * 1123529253211.0 + index * 10123457689.0;
long num2 = Double.doubleToRawLongBits(num);
return (int) ((num2 >> 42) ^ (num2 >> 21) ^ num2);
}
If it's large and sparse you can use a hash table (downside: the numbers you get depend on your access pattern).
Otherwise you could recycle the solution to a problem from the Programming Pearls (search for something like "programming pearls initialize array"), but it wastes memory iirc.
Last solution I can think of, you could use a random generator which can efficiently jump to a specified position - the one at http://mathforum.org/kb/message.jspa?messageID=1519417 is decently fast, but it generates 16 numbers at a time; anything better?

Generate random double from random long

in Java I have a random generator that generates random number from -2^63 to 2^63 and that is NOT the java.util.Random.
I need to generate random double in (0,1), this is what I've done so far:
return (seed/(double)(9223372036854775807L))/2+0.5;//seed is a random long
Is this right? Are there any numerical problem (underflow?)?
Could be better/faster?
Thank you.
I would use Math.scalb as the most efficient and ensures there is no funny behaviour due to rounding or representation error
double d = Math.scalb(seed >>> 1, -63);
You can only use 53 bits in a double so some will be discarded.
If you run
long seed = Long.MAX_VALUE;
System.out.println(Math.scalb(seed >>> 1, -63));
prints
0.5
With a seed of 0 you get 0.0
With a seed of -1 you get 1.0
I would prefer to see just a single division.
0.5+(seed/1.84467440737096E+19);
That said, you are going to run up against issues with floating point accuracy since you have 64 random integer bits which you then try to squeeze into 53 bits of double precision. You may be better off making a dedicated generator for floating point values, but I could not say for sure since I don't know your motivation.
The fastest way would probably just be to set the first three bits in your long to 0 and then use those bits to make a double.:
double rand = Double.longBitsToDouble(seed & 0x1FFFFFFFFFFFFFFFL);
This works by forcing the sign to positive, and exponent to be less than 0, which will cause the mantissa to be shifted right at least once. It gives an even distribution assuming all the ints in the long are completely random. Here is a full Java program that uses Random to generate random longs, and then this method to convert them to double's between 0 and 1:
import java.util.Random;
class Main{
public static void main(String[] args){
Random rand = new Random();
long seed = rand.nextLong();
double x = Double.longBitsToDouble(seed & 0x1FFFFFFFFFFFFFFFL);
System.out.println(x);
}
}
This is the output of 10 executions:
1.1211565592484309E-247
8.84224349357039E-242
6.956043405745214E-271
3.747746366809532E-232
9.302628573486166E-158
1.1440116527034282E-166
1.2574577719255876E-198
5.104999671234867E-269
3.360619724894072E-213
1.5654452507283312E-220
Edit
This gives a uniform distribution of all possible doubles between 0 and 1. Since there are many more small doubles you will likely never see a number close to 1. You can fix this by generating a new exponent based on the bits of the existing one, but you need a loop to do it, so it probably isn't the fastest method after factoring this in:
long exponent = 0;
for(int i = 52; (seed >>> i & 1) > 0; i++) exponent++;
double x = Double.longBitsToDouble(seed & 0x000FFFFFFFFFFFFFL | ((1022 - exponent) << 52));
0.4773960377161338
0.929045618651037
0.7183096209363845
0.33962049395497845
0.45568660174922454
0.11670190555677815
0.09371618427480996
0.8192870898479095
0.9365016017283178
0.11311614413193898
Not exactly. I think that easier way is to do the following:
new Random(seed).nextDouble()
Unless I'm misreading your need to have a random double from 0 to 1, Java's built in Math.random does just that. So you could avoid all the conversion you are currently doing.

Categories