java random number generator - lottery - java

My code will seem amateurish as I am a software engineering student in 2nd year.
I created a lottery number generator and have noticed peculiar but consistent results. My program attempts to match the previous lottery numbers for the Euro Millions draw. I track the number of attempts it takes and i also track the number of times I match 3, 4, 5 and 6 numbers.
The attempts range between 1 million and 422 million. i.e. I would run the program 10 times and I would achieve a range, I would also track the length of time each run takes.
I account for a number of things like preventing a random number from being used more than once and this check is done against a HashMap of the possible lottery numbers. If I find the random number within the hashmap I add the number to an arraylist and then remove the number from the hashmap.
My questions surrounds the results.
In all attempts to match the lottery numbers my chance of getting 3 numbers was 3.13% on average. For 4 numbers it dropped to 0.28%, 5 numbers 0.00012% and 6 numbers 0.00022%.
Understandably The chance of winning as the number of lottery numbers increase is going to decrease however whether I had 1 million or 100 million attempts the ratio was the same or extremely close.
If you are interested my smallest number of attempts was 1,088,157, it took approximately 6 seconds or 6612ms.
Largest number of attempts was 422,036,905 and it took 26mins or 1589867ms.
Since I am using the Java Random library I am merely looking for some clarity on this. Or should I simply put it down to probability?
My code is an unnecessary 225 lines, if you would like to see a particular part or prefer to see the whole thing then please request this. Here is a sample below of the random number generation for the first 5 numbers.
//stores all possible lottery numbers
public static HashMap<Integer,Integer> randRange = new HashMap<Integer,Integer>();
//stores bonus ball numbers
public static HashMap<Integer,Integer> boRange = new HashMap<Integer,Integer>();
//stores lottery number output
public static ArrayList<Integer> lotNum = new ArrayList<Integer>();
//stores bonus ball output
public static ArrayList<Integer> boNum = new ArrayList<Integer>();
public static void randomInt(){
Random rand = new Random();
//generate a random number
int RandInt = rand.nextInt(51);
int boInt = rand.nextInt(12);
//loop used to get unique random number
int count=0;
while(count!=5){
//check if random number exists
if(randRange.get(RandInt)!=null)
{
//finalise random number
RandInt=randRange.get(RandInt);
//add to ArrayList
lotNum.add(RandInt);
//remove number
//ensures next random number is unique
randRange.remove(RandInt);
count++;
}
else
{
//get a new random number
//and start process again
RandInt = rand.nextInt(51);
}
}
}
EDIT:
First of all sorry I couldn't upvote as I have less than 15 reputation. All answers were helpful including comments.
Thanks to the suggestions by all members I improved my program and discovered unsurprisingly a fault in my code. #digitaljoel you were correct in the probability of matching 5 and 6 numbers. I set up the calculation incorrectly, e.g. for the numbers 11,20 30,35,45,2,3 for the euromillions draw to match 3 was 0.7%, 4 was .05%, 5 was .00273% and 6 was .000076%.
Thanks to #maybewecouldstealavan I changed my shuffling method to simply populate an ArrayList and shuffle the list, get the first five numbers and do the same for the bonus balls. The benefit was in the number of checks per second increasing from 150 - 200 thousand checks per second to 250-700 thousand checks per second.
Thanks to #trutheality as in some cases if i checked 1000 or 1,000,000 matches the variation was similar or minute.
#LeviX Appreciate again the calculation for the possible combinations. I used this within the program and found that it took more than the total number of combinations to win the lottery. Most likely I am producing duplicate random numbers. From this i will probably create all possible combinations and randomly select each combination until the program finds a match.

In all attempts to match the lottery numbers my chance of getting 3 numbers was 3.13% on average. For 4 numbers it dropped to 0.28%, 5 numbers 0.00012% and 6 numbers 0.00022%.
Understandably The chance of winning as the number of lottery numbers increase is going to decrease however whether I had 1 million or 100 million attempts the ratio was the same or extremely close.
That is actually not surprising at all. What you end up doing here is estimating the probability of guessing 3,4,5, or 6 numbers correctly. Having more samples will only make the variations in your estimates smaller, but even with "as little" as 1 million samples, your estimate is expected to be close to the exact probability (which you could calculate by doing some math).

Do you mean that you expect the proportion of times that you win to be more "random"? If that's what you're getting at, then #truthreality is quite correct. For further reading you might look at the law of large numbers and the central limit theorem.
If you're asking if your method of shuffling is correct, it is though it is inefficient. You're generating more random numbers than necessary, since you're just checking for dupes when they occur, and you're not creating a new random number after you pick a ball, so you're requiring a minimum of one HashMap.get(int) per pick.
I might use one of the following methods instead:
1) Create an ArrayList containing all the ball values. For each drawing, use Collections.shuffle(yourArrList, rand) to shuffle a clone of it them, then just use the first 5 balls from the list.
2) Again, create an Array or ArrayList of ball values. Then implement a portion of the shuffle operation yourself: Choose from smaller and smaller subsets of the possibilities and swap in the element that no longer fits into the place of the element that was just chosen. The advantage is that you don't need to shuffle the entire array. Here's my quick and dirty implementation:
public static int[] choose(int[] array, int count, Random rand) {
int[] ar = array.clone();
int[] out = new int[count];
int max = ar.length;
for (int i = 0; i<count; i++) {
int r = rand.nextInt(max);
//max is decremented,
//the selected value is copied out then overwritten
//by the last value, which would no longer be accessible
max--;
out[i]=ar[r];
ar[r]=ar[max];
}
return out;
}
There's probably room for improvement, especially if order doesn't matter.

From my understanding there are two different parts to the Euro Millions. The 5 balls and then the 2 bonus balls. You can check the math of your program by figuring out the exact probabilities of winning. I'm sure you can google it, but it's easy to calculate.
Probability of getting 5 balls out of 50 (order doesn't matter)
P(A) = 50!/5!(50-5)! = 2,118,760
Probability of getting 2 balls out of 11 (order doesn't matter)
P(B) 11!/2!(11-2)! = 55
The two events are independent so multiply them together.
P(A) * P(B) = P(A&B)
2,118,760 * 55 = 116,531,800
Therefore the chances of winning the lottery is:
1 in 116,531,800

Related

Adding random numbers 1-1000000 in an array?

I have looked up how to add 0-99 to an array. But, my assignment was 1-1000000. I just keep getting really large numbers and no small numbers. Is it just because the chance of getting large numbers is a lot higher? I just wanted to make sure I was doing it right. Thanks in advance for any help!
int a[]= new int[50];
for(int i = 0; i < 50; i++) {
a[i] = (int)(Math.random() * 10000000);
}
Depends what do you call by small numbers.
For example, getting number lower than 1000 means that it would need to fit to lower 0.1% of the interval as 1000 it's just 0.1% of all the numbers from 1 million.
Additionally, note that this way you'll get numbers between 0 and 999999 (inclusive). To get 1-1000000 you need to add 1:
a[i] = (int)(Math.random() * 10000000)+1;
Well if you hoped to get a number below 1000, there's a 1/10000 chance, which translates to 0.01%. Your code is fine, but with these settings getting a low number is quite unlikely
Yes, large numbers will dominate with that. That's because half the numbers are over 500,000. Similarly, 9/10 of the numbers are over 100,000. So 9/10 of the numbers will have six digits.
[Somewhat orthogonal solution to your question]
One of the options you can consider is to shuffle the array after adding the numbers based on your expected distribution, which can be all numbers added once/certain numbers added multiple times/certain prime numbers multiple times, etc.
I personally used it to cover some cases for a game development.
Here is an answer which can help you shuffle: Credits
List<Integer> solution = new ArrayList<>();
for (int i = 1; i <= 6; i++) {
solution.add(i);
}
Collections.shuffle(solution);

Roll Die JAVA Program using Array

I have difficulty in understanding some line of code in this roll die JAVA program using arrays.
This program notes the frequency of the numbers 1-6 and then displays in console.
import java.security.SecureRandom;
public class RollDie{
public static void main(String[] args){
SecureRandom randomNumbers=new SecureRandom();
int[] frequency=new int[7]; //array of frequency counter
//roll die 6000000 times, use die value as frequency index
for(int i=1; i<=6000000;i++)
++frequency[1+randomNumbers.nextInt(6)];
System.out.printf("%s%10s%n","face","frequency");
for(int face=1;face<frequency.length;face++)
System.out.printf("%4d%10d%n", face, frequency[face]);
}
}
can anyone explain this line:
++frequency[1+randomNumbers.nextInt(6)];
The line is written quite unclearly. I took a long time comprehending it as well.
First, we see the ++ prefix operator. You know what it does right? It increments the variable on the left before any other operators are evaluated. Since there aren't any other operators, it just increments frequency[1+randomNumbers.nextInt(6)] by 1.
So what is this frequency[1+randomNumbers.nextInt(6)] thingy?
First, you would see that it is accessing the array frequency, since there are those [] things. So which index to access? Well, 1+randomNumbers.nextInt(6)!
nextInt(x) returns a uniformly distributed random number between 0 and x-1. nextInt(6) returns a random number between 0 and 5. But a typical dice roll always results in 1 - 6! That's why we need to add 1 to the return value of nextInt. As a result, the index will be between 1 - 6.
Thus, as a whole, this whole line just rolls the dice (1+randomNumbers.nextInt(6)), and increment the corresponding index of the array frequency.
It would probably be easier to read if it were written like this:
int diceRoll = randomNumbers.nextInt(6);
frequency[diceRoll]++;
I have divided it in execution sequence to be easier to comprehend. The order of evaluation follows the following sequence:
1.randomNumbers.nextInt(6) Gets a random number from 0 to 5 inclusive
2. 1 + randomNumbers.nextInt(6) - adds one
frequency[1+randomNumbers.nextInt(6)] - Extracts the value from frequency under the already calculated index.
++frequency[1+randomNumbers.nextInt(6)] - *adds 1 to that element in frequency *
The difference between the old frequency value and the new frequency value on that position is 1.
Essentially this question relates to the precedence of operators in Java and has been already discussed in details here
What are the rules for evaluation order in Java?

Generate N random numbers in given ranges that sum up to a given sum

first time here at Stackoverflow. I hope someone can help me with my search of an algorithm.
I need to generate N random numbers in given Ranges that sum up to a given sum!
For example: Generatare 3 Numbers that sum up to 11.
Ranges:
Value between 1 and 3.
Value between 5 and 8.
value between 3 and 7.
The Generated numbers for this examle could be: 2, 5, 4.
I already searched alot and couldnt find the solution i need.
It is possible to generate like N Numbers of a constant sum unsing modulo like this:
generate random numbers of which the sum is constant
But i couldnt get that done with ranges.
Or by generating N random values, sum them up and then divide the constant sum by the random sum and afterwards multiplying each random number with that quotient as proposed here.
Main Problem, why i cant adopt those solution is that every of my random values has different ranges and i need the values to be uniformly distributed withing the ranges (no frequency occurances at min/max for example, which happens if i cut off the values which are less/greater than min/max).
I also thought of an soultion, taking a random number (in that Example, Value 1,2 or 3), generate the value within the range (either between min/max or min and the rest of the sum, depending on which is smaller), substracting that number of my given sum, and keep that going until everything is distributed. But that would be horrible inefficiant. I could really use a way where the runtime of the algorithm is fixed.
I'm trying to get that running in Java. But that Info is not that importend, except if someone already has a solution ready. All i need is a description or and idea of an algorithm.
First, note that the problem is equivalent to:
Generate k numbers that sums to a number y, such that x_1, ..., x_k -
each has a limit.
The second can be achieved by simply reducing the lower bound from the number - so in your example, it is equivalent to:
Generate 3 numbers such that x1 <= 2; x2 <= 3; x3 <= 4; x1+x2+x3 = 2
Note that the 2nd problem can be solved in various ways, one of them is:
Generate a list with h_i repeats per element - where h_i is the limit for element i - shuffle the list, and pick the first elements.
In your example, the list is:[x1,x1,x2,x2,x2,x3,x3,x3,x3] - shuffle it and choose first two elements.
(*) Note that shuffling the list can be done using fisher-yates algorithm. (you can abort the algorithm in the middle after you passed the desired limit).
Add up the minimum values. In this case 1 + 5 + 3 = 9
11 - 9 = 2, so you have to distribute 2 between the three numbers (eg: +2,+0,+0 or +0,+1,+1).
I leave the rest for you, it's relatively easy to create a uniform distribution after this transformation.
This problem is equivalent to randomly distributing an excess of 2 over the minimum of 9 on 3 positions.
So you start with the minima (1/5/3) and then cycle 2 times, generating a (pseudo-)random value of [0-2] (3 positions) and increment the indexed value.
e.g.
Start 1/5/3
1st random=1 ... increment index 1 ... 1/6/3
2nd random=0 ... increment index 0 ... 2/6/3
2+6+3=11
Edit
Reading this a second time, I understand, this is exactly what #KarolyHorvath mentioned.

Generating Random Numbers from 1-100

int getnum50()
{
Random rand = new Random();
return (1+rand.nextInt(50));
}
You are given a predefined function named getnum50() which returns an
integer which is one random number from 1-50.
You can call this function as many times as you want but beware
that this function is quite resource intensive.
You cannot use any other random generator. You can NOT change the
definition of getnum50().
Print numbers 1-100 in random order. (Not 100 random numbers)
Note:
i. Every number should be printed exactly once.
ii. There should be no pattern in the numbers listing. List should be
completely random i.e., all numbers have equal probability
appearing at any place.
iii. You may call getnum50() any number of time to get random number
from 1 to 50 but try to make the code optimised.
iv. You cannot use any other random generator function except
getnum50().
I wrote some code which was showing correct output.
import java.util.Random;
public class RandomInteger{
int number[]=new int[100];//To store numbers in random order
public RandomInteger(){
int n[]=new int[100];//array to store which random numbers are generated
int off[]={-1,0};//offset to add
System.out.println("Length of array number100 is:"+number.length);
System.out.println("Generating random numbers in the range 1-100:");
for(int n1=0;n1<number.length;n1++){
int rnd=off[(getnum50()-1)/50]+(getnum50()*2);
if(n[rnd-1] == 0){
n[rnd-1]=1;//to indicate which random number is generated
number[n1]=rnd;
System.out.println(number[n1]+" ");
}
}
}
//end of constructor
int getnum50(){
Random rand = new Random();
return (1+rand.nextInt(50));
}
public static void main(String args[]){
RandomInteger m= new RandomInteger();
}
//end of main()
}
//end of class
While it was accepted in that round, in the next round the interviewer tells me that getnum50() is a costly method and even in best case scenario I have to call it twice for every number generated. i.e. 200 times for 1-100. In worst case scenario it would be infinity and tens of thousand in average case. He asks me to optimize the code so as to significantly improve the average case.
I could not answer.So please give me proper answer for the question? How will I optimize my above code??
One stupid optimization would be be to just realize that since your randomized source is limited to 1-50, you might as well set TWO array positions, e.g.
rand = getnum50();
n[rand] = 1;
n[rand+50] = 1;
Now the array will be slightly "less" random, because every index n is going simply be 1/2 of whatever's at n+50, but at least you've cut ~half the build array construction time.
I think they want you to produce a shuffle algorithm.
In this, you start with an array of exactly 100 numbers ( 1 through 100 in order ), and then on each iteration you shuffle the numbers.
Do it enough times, and the original array is completely random.
The 50 is a red herring. Use two calls to random50, mod 10. Now you have two digits: tens and ones place. This gives you a random100() function.
The real killer is the generate-and-check approach. Instead, put the numbers 1-100 into an arraylist, and use your random100 to REMOVE a random index. Now your worst case scenario has 2n calls to random50. There's a few problems left to solve - overruns - but that's the approach I'd look at.
Your problem us that if you are toward the end of the list you will have to generate lots of random numbers to get a number in the couple of spots left. You could reduce a couple of ways one the fits into your current answer fairly will is as follows:
while(n[rnd-1] == 1)
{
rnd++;
rnd=end%101;
}
n[rnd-1]=1;//to indicate which random number is generated
number[n1]=rnd;
System.out.println(number[n1]+" ");
However if you assume that the getnum50 is more expensive than anything you can write you could reduce the number of getnum50 that you call while filling in the second half of the list. Each time you find a number you could reduce your search space by one so (using non primitives):
while(myArrayList.size()>1)
{
int rnd=0;
if(myArrayList.size()>50);
rnd=((getnum50()-1)/50)+((getnum50()*2)%myArrayList.size())+1;
else
rnd=getnum50()%myArrayList.size()+1;
System.out.println(rnd);
myArrayList.remove(rnd);
}
System.out.println(myArrayList.get(rnd);
myArrayList.remove(rnd);
In this example your best, average and worst are 149 getnum50 calls;
The reason you are calling the method getnum50() twice is because of this line:
int rnd = off[(getnum50()-1)/50] + (getnum50()*2);
which seems self-explanatory. And the reason your worst case scenario is so bad is because of this block:
if(n[rnd - 1] == 0){
n[rnd - 1] = 1; //to indicate which random number is generated
number[n1] = rnd;
System.out.println(number[n1] + " ");
}
Depending on how bad your luck is, it could take a very long time to get each value. So, best case, you make your two getnum50() calls, which WILL happen the first time, but as you fill up your array, it becomes increasingly less likely. For 100 numbers, the last number will have a 1% chance of success on the first time, and every time it fails, you make another two calls to getnum50().
Sorry, this doesn't answer HOW to improve your efficiency, but it does explain why the efficiency concerns. Hope it helps.

probability and programming simulation

I'm having some trouble understanding the following result.
I want to know if the following code is actually correct. It stumps me - but that could be due to me misunderstanding the probability involved.
The code should speak for itself, but to clarify the 'real world' simulation represents 2 people flipping a coin. When you lose you pay 1 dollar, when you win you win a dollar. An even sum game!
private static Random rnd = new Random();
public static void main(String[] args) {
int i=0;
for (int x = 0; x<1000000; x++) {
if (rnd.nextBoolean()) i+=1;
else i-=1;
}
System.out.println(i);
}
When I run this however I get huge swings! Whilst I would expect a large sample like this to converge to 0, I'm seeing +-4000
Not only that but increasing the sample size seems to only make the swings higher.
Am I misusing the random function ? :P
I think you're good. The thing to look at is the ratio of the swing to your sample.
4000 out of 1000000 for example is 0.4%
If you increase the sample size, you should expect that ratio to go down.
The results of your experiment should follow a binomial distribution. If the
number of trials is N, and the probability of success p=1/2, then the
number of successes N_success (for large enough N) should have a mean of approximately Np,
and standard deviation sqrt(N*p*(1-p)).
You're actually tracking K = (N_success - N_fail). So N_success = N/2 + K/2.
With 1,000,000 trials and K=4000, we get N_success = 502000. The expected
value is 500000, with standard deviation sqrt(250000) = 500. The difference
between the observed and expected values of N_success is 2000, or about 4 sigma.
That's significant enough to question whether the random number generator is
biased. On the other hand, if you're running this test thousands of times,
you'd expect a few outliers of this magnitude, and you seem to be seeing both
positive and negative values, so in the long run maybe things are OK after all.
You are simulating a one-dimensional random walk. Basically, imagine yourself standing on a line of integers. You begin at point i=0. With equal probability you take a step to the right or the left.
The random walk has a few cool properties and you've touched on my favourite:
Starting at point i=0, as N gets larger, the probability that you will return to that point approaches 1. As you point out - a zero sum game.
However, the expected time it will take you to return there tends to infinity. As you notice, you get some very large swings.
Since the average value should be 0 and the variance of N moves is N, then you would expect 95% of your simulations to end in the region: (- 1.96, 1.96)*N^(0.5).

Categories

Resources