Fastest way to generate two random numbers from the same range - java

I've been making a little game in Java and I'm using the Java Random class to generate random number.
During the course of the game, two teams play one another, and to figure out who wins the match, I generate two random numbers (from 1 to 10, like a d10) and then do some modifications to those scores, comparing them to find out who wins.
But I was wondering if there was a more efficient way to do it. I don't really know exactly how the Java Random class works, but my idea was that I would instead generate a single random number (from 1 to 100) and then integer divide by 10 to get one of the numbers and then do mod 10 to find the other number.
In code, my question is which of these is faster:
Random r = new Random();
int team1Score;
int team2Score;
int randNum;
// current version
team1Score = r.nextInt(10) + 1;
team2Score = r.nextInt(10) + 1;
// new version
randNum = r.nextInt(100) + 1;
team1Score = randNum / 10;
team2Score = randNum % 10;
And if, anyone has any ideas, is there any way to make it even more efficient than either of these?

This is an example of premature optimization. The difference between these two examples is incredibly small, and you really shouldn't worry about it. I'd go with the first for the sake of readability.

Related

Generating a sequence of Pseudo-random numbers based on a seed

In Java, I want to generate a program that generates a string of around 15 numbers based on a seed. It always needs to be from 1 to 9. It should seem random, but each seed spits out the same sequence.
For example if you type the number 5, it might output 194639573978476, but if you enter 6, it would output 657362047273958, and 5 will always output 194639573978476.
How do i do this?
First :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.
Source:Oracle
For this reason the seed needs to be different every time to generate a different numbers. You can use the time as seed. Like this,
Random random = new Random(System.currentTimeMillis());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 15; i++) {
sb.append(Integer.toString((random.nextInt(9) + 1)));
}
System.out.println(sb.toString());
Sample output every time you run the code:
146645139262732
919846574753947
662686147977574
Hope this helps!
First, create an instance of Random and give it your seed as an argument:
Random rand = new Random(seed);
Then just get 15 numbers. You can use a stringbuilder to build the string, or any other way you want. Shouldn't be too hard, but here's a quick and dirty way to do it:
String result = "";
for(int i = 0; i < 15; i++) {
result += rand.nextInt() % 9 + 1;
}
Please note this is some very dirty programming, did it this way for the sake of simplicity and readability. This is very poor style and you shouldn't copy paste this without changing it.

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

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?

Generating Random integers within a range to meet a percentile in java

I am trying to generate random integers within a range to sample a percentile of that range. For example: for range 1 to 100 I would like to select a random sample of 20%. This would result in 20 integers randomly selected for 100.
This is to solve an extremely complex issue and I will post solutions once I get this and a few bugs worked out. I have not used many math packages in java so I appreciate your assistance.
Thanks!
Put all numbers in a arraylist, then shuffle it. Take only the 20 first element of the arraylist:
ArrayList<Integer> randomNumbers = new ArrayList<Integer>();
for(int i = 0; i < 100; i++){
randomNumbers.add((int)(Math.random() * 100 + 1));
}
Collections.shuffle(randomNumbers);
//Then the first 20 elements are your sample
If you want 20 random integers between 1 and one hundred, use Math.random() to generate a value between 0 and 0.999... Then, manipulate this value to fit your range.
int[] random = new int[20];
for(int i =0; i< random.length;i++)
{
random[i] = (int)(Math.random()*100+1);
}
When you multiply Math.random() by 100, you get a value between 0 and 99.999... To this number you add 1, yielding a value between 1.0 and 100.0. Then, I typecasted the number to an integer by using the (int) typecast. This gives a number between 1 and 100 inclusive. Then, store the values into an array.
If you are willing to go with Java 8, you could use some features of lambdas. Presuming that you aren't keeping 20% of petabytes of data, you could do something like this (number is the number of integers in the range to get) it isn't efficient in the slightest, but it works, and is fun if you'd like to do some Java 8. But if this is performance critical, I wouldn't recommend it:
public ArrayList<Integer> sampler(int min, int max, int number){
Random random = new Random();
ArrayList<Integer> generated = new ArrayList<Integer>();
IntStream ints = random.ints(min,max);
Iterator<Integer> it = ints.iterator();
for(int i = 0; i < number; i++){
int k = it.next();
while(generated.contains(k)){
k = it.next();
}
generated.add(k);
}
ints.close();
return generated;
}
If you really need to scale to petabytes of data, you're going to need a solution that doesn't require keeping all your numbers in memory. Even a bit-set, which would compress your numbers to 1 byte per 8 integers, wouldn't fit in memory.
Since you didn't mention the numbers had to be shuffled (just random), you can start counting and randomly decide whether to keep each number or not. Then stream your result to a file or wherever you need it.
Start with this:
long range = 100;
float percentile = 0.20f;
Random rnd = new Random();
for (long i=1; i < range; i++) {
if (rnd.nextFloat() < percentile) {
System.out.println(i);
}
}
You will get about 20 percent of the numbers from 1 to 100, with no duplicates.
As the range goes up, the accuracy will too, so you really wouldn't need any special logic for large data sets.
If an exact number is needed, you would need special logic for smaller data sets, but that's pretty easy to solve using other methods posted here (although I'd still recommend a bit set).

Random generated number

How would you set up a program using Java to generate a 5 digit number using the following statement:
int n = (int)Math.floor(Math.random()*100000+1)
It also has to print the number generated. I have tried writing this different ways and keep coming up with errors.
There are two ways of looking at your problem. Either you need to make sure the random number generator only produces numbers with exactly five digits (in the range 10000 - 99999) or you need to print the numbers with leading 0s when a number is produced that's too low.
The first approach is best met using Java's Random class.
Random rand = new Random();
int n = rand.nextInt(90000) + 10000;
System.out.println(n);
If you're restricted in some way that you must use the statement in your question, then the second approach is probably what you're after. You can use Java's DecimalFormat class to format a random number with leading zeros before printing.
n = (int)Math.floor( Math.random() * 100000 + 1 );
NumberFormat formatter = new DecimalFormat("00000");
String number = formatter.format(n);
System.out.println("Number with lading zeros: " + number);
One might do:
public class Test {
public static void main(String[] args) {
int n = (int)Math.floor(Math.random()*100000+1);
System.out.println(n);
}
}
However, this really isn't the preferred way of generating random integers. Check out the Random class.
Random r = new Random();
for (;;) {
System.out.println(10000 + r.nextInt(90000));
}
A better idea is to generate the number by successively generating 5 random digits. Making the first digit non-zero ensures that the generated number is always 5-digit. I'm posting pseudocode below, it should be easy to convert it into Java code.
A = List(1,2,3,4,5,6,7,8,9)
B = List(0,1,2,3,4,5,6,7,8,9)
output = 0
output=random.choice(A) //first digit from A, no zeros
for i=0 to 4
output=output*10
output=output+random.choice(B) //next digits from B, can have zero
return output
Look up the API docs for Random if you are stuck.
A way to get a random number 00000 - 99999 is to use the following.
Random r= new Random();
// possibly too obtuse for most readers. ;)
System.out.println((""+(100000+r.nextInt(100000))).substring(1));

Categories