Thread: match probability is correct for a full match but not for a partial match

  1. #1
    Registered User
    Join Date
    Nov 2004
    Posts
    6

    match probability is correct for a full match but not for a partial match

    I created a C program that provides stats on random number (lotto) matches. The calculated probability of a full match equals the programs average output for a full match, but a partial match, like matching 3 out of the 6 numbers, is always significantly higher for the program than the calculated probability.

    example: 6/49 match 6 probability is around 1 in 13.9 million, my program consistently has an average around 13-14 million.

    example: 6/49 match 3 probability is around 1 in 57, my program consistently has an average of mid 900s.

    My compiler is MinGW. I am using the 64-bit version of Mersenne Twister pseudorandom number generator to generate my random numbers.

    The program flow is as follows:
    - The user inputs a max (ex: 49), a pick amount (ex: 6), a match amount(ex: 3), and the number of draws to perform
    - The user enters 3 random numbers (ex: 7 18 44)
    - The program then generates a random set of 6 numbers (checking for duplicates) from the max of 49, and stores them in an array
    - Once the program has 6 numbers with no duplicates, it performs a match check to see if the user's 3 numbers match any of the computer's six numbers
    - A loop counter is increased by 1 for each match check. If there is no match, the computer picks another set of 6 random numbers and checks for a match
    - this process repeats until the computer's 6 numbers contains the 3 numbers that the user entered
    - the program outputs a running average of how many attempts it took to match 3 out of the 6 computer picked numbers
    - the match-attempts and switch statement is something new that I added, the probability problem existed prior to it

    Is there a mistake in my logic while generating the random numbers and checking for a match? I have dissected the code numerous times, and I cannot see what the problem might be.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
    #include <time.h>
    
    #include <random2.h> //place in C:\MinGW\include folder
    
    #define ARRAYSIZE 100
    
    //typedef enum {false, true} bool;
    bool checkArray(int currentIndex, int number, int array[]);
    bool checkMatch(int arrayInput[], int arrayRandom[], int picks, int amttomatch);
    void sort( int array[], int picks);
    void print(int array[], int picks);
    void switch_print(double loop, double average, double DrawLoopCount, double draw_span);
    void printToFile(int array[], double loop, bool match, int picks, int amttomatch);
    
    int roll (int max);
    
    int main() {
        bool duplicate;
        bool match;
    	char quit, rml_condition;
        int indexR, indexI, input, pick, max;
        int inputNumbers[ARRAYSIZE], randomNumbers[ARRAYSIZE], picks, amttomatch, reachMatchLoop;
        double loop=0, total=0, average=0, draws=0, DrawLoopCount=1, previous_DrawLoopCount=0, reachMatchLoop_count=0;
    	double draw_span=0, draw_span_total=0, draw_span_avg=0;
        FILE *fp1;// File pointer
    
    	//seed random number generator rand
        time_t t;
    	//srand((unsigned) time(&t));
    
    	//seed random number generator in random2.h
        init_genrand64(time(&t));
        
        printf("Lottery Probability\n\n");
        while(quit != 'q'){
           //User inputs array of numbers
           printf("Enter a max number: ");
           scanf("%d", &max);
    	   
    	   printf("Set match-attempts (ex. 16 means track amount of times it took 16 or more attempts to reach a match [enter 0 to skip this]: ");
    	   scanf("%d", &reachMatchLoop);   
    	   
    	   if(reachMatchLoop != 0){
             while(rml_condition != 'g' && rml_condition != 'l' && rml_condition != 'e'){
    		   _flushall();
    		   printf("(g)reater than, (l)ess than, or (e)qual to %d: ", reachMatchLoop);
    	       //scanf("%c",&rml_condition);
    		   rml_condition = getchar();
    		   printf("\n");
    		 }
    	   }
    	   
           printf("How many numbers (from %d) to pick: ", max);
           scanf("%d", &picks);
    	   
    	   printf("How many numbers to match out of the %d picks: ", picks);
           scanf("%d", &amttomatch);
    	   
           printf("Enter number of draws to perform: ");
           scanf("%lf", &draws);
    	   
    	   //User inputs random numbers in range of max in amount of numbers to match 
           printf("\nInput %d numbers from 1 - %d\n", amttomatch, max);
    	   for(indexI=0; indexI<amttomatch; indexI++){
              inputNumbers[indexI]=0;
           }
    	   //print(inputNumbers,ARRAYSIZE);
    	   
           for(indexI=0; indexI<amttomatch; indexI++){
              do{
                 printf("Entry%d: ",indexI+1);
                 scanf("%d", &input);
                 duplicate = checkArray(indexI,input,inputNumbers);
              }while((input<1 || input > max) || duplicate);
              inputNumbers[indexI]=input;
           }
           printf("\n");
    	   
           //Computer generates array of numbers with no duplicates, and checks picks for a match with input
    	   for(DrawLoopCount=1; DrawLoopCount<=draws; DrawLoopCount++){
               match = false;
               while(!match){
                  for(indexR=0; indexR<picks; indexR++){
    				 randomNumbers[indexR]=0;
    			  }
                  for(indexR=0; indexR<picks; indexR++){
                     do{
                        pick = roll(max);
                        duplicate = checkArray(indexR,pick,randomNumbers);
    					//printf("%2.0f | %d ", loop,pick);
    					//printf("dup=%s\n", duplicate ? "true" : "false");
                     }while(duplicate);
                     randomNumbers[indexR]=pick;
    				 //printf("%2.0f R=%d\n", loop,pick);
                  }
    			  
                  match = checkMatch(inputNumbers, randomNumbers, picks, amttomatch);
                  loop++;
    			  //print(randomNumbers,picks);
    			  //printf("%2.0f ", loop);
    			  //printf("match=%s\n", match ? "true" : "false");
    			  
    			  //printToFile(randomNumbers,loop,match,picks,amttomatch);
               }
               total+=loop;
               average = total/DrawLoopCount;
    		   
    		   switch(rml_condition) {
    			 case 'g': 
    			   if(loop >= reachMatchLoop){
    				   reachMatchLoop_count++;
    				   draw_span = DrawLoopCount-previous_DrawLoopCount;
    				   draw_span_total+=draw_span;
    				   draw_span_avg = draw_span_total/reachMatchLoop_count;
    				   
    				   switch_print(loop, average, DrawLoopCount, draw_span);
    				   
    				   printf ("Draw Span Avg from %2.0lf attempts per match >= %d: %4.2lf  |  \n", reachMatchLoop_count, reachMatchLoop,draw_span_avg);
    				   previous_DrawLoopCount = DrawLoopCount;
    			   }
    			 break;
    			 
    			 case 'l':
    			   if(loop <= reachMatchLoop){
    				   reachMatchLoop_count++;
    				   draw_span = DrawLoopCount-previous_DrawLoopCount;
    				   draw_span_total+=draw_span;
    				   draw_span_avg = draw_span_total/reachMatchLoop_count;
    				   
    				   switch_print(loop, average, DrawLoopCount, draw_span);
    				   
    				   printf ("Draw Span Avg from %2.0lf attempts per match <= %d: %4.2lf  |  \n", reachMatchLoop_count, reachMatchLoop,draw_span_avg);
    				   previous_DrawLoopCount = DrawLoopCount;
    			   }
    			 break;
    			 
    			 case 'e':
    			   if(loop == reachMatchLoop){
    				   reachMatchLoop_count++;
    				   draw_span = DrawLoopCount-previous_DrawLoopCount;
    				   draw_span_total+=draw_span;
    				   draw_span_avg = draw_span_total/reachMatchLoop_count;
    				   
    				   switch_print(loop, average, DrawLoopCount, draw_span);
    				   
    				   printf ("Draw Span Avg from %2.0lf attempts per match = %d: %4.2lf  |  \n", reachMatchLoop_count, reachMatchLoop,draw_span_avg);
    				   previous_DrawLoopCount = DrawLoopCount;
    			   }
    			 break;
    			 
    			 default:
    			   printf ("Attempts: %10.0lf | ", loop);
    			   printf ("Average: %11.2lf | ", average);
    			   printf ("Draw Counter: %0.0lf\n", DrawLoopCount);
    			 break;
    		   }
    		   
               loop=0;
           }
    	   
           fp1 = fopen("matchAnyPartial.txt", "a");
           fprintf (fp1,"%d/%-4d", picks, max);
           fprintf (fp1,"Average Attempts: %11.2lf   ", average);
           fprintf (fp1,"Loop Count: %4.0lf ", DrawLoopCount-1);
    	   fprintf (fp1,"Match Picks: %2d\n", amttomatch);
           fclose (fp1);
    	   
           printf("\n");
           printf("Your Numbers:");
           sort(inputNumbers,amttomatch);
           print(inputNumbers,amttomatch);
    	   
    	   printf("\n");
           printf("Matched Numbers %d of %d:", amttomatch, picks);
           sort(randomNumbers,picks);
           print(randomNumbers,picks);
           
    	   printf("\n");
    
           loop=0;
           total=0;
           average=0;
    	   reachMatchLoop=0;
    	   reachMatchLoop_count=0;
           DrawLoopCount=1;
    	   previous_DrawLoopCount=0;
    	   rml_condition='\0'; //clear char variable
    	   draw_span=0;
    	   draw_span_total=0;
    	   draw_span_avg=0;
    	   
           printf ("Hit enter to go again.  Hit 'Q' to exit\n");
           _flushall();
           quit = getchar();quit=tolower(quit);  
        }
    	return 0;
    }
    
    /* Compare input array with rand array for a match */
    bool checkMatch(int arrayInput[], int arrayRandom[], int picks, int amttomatch){
       int indexR=0, indexI=0, amount=0;
       bool match;
       //printf("Check for match\n");
       //print(arrayInput,amttomatch);
       //printf("\n");
       //print(arrayRandom,picks);
       for(indexR; indexR<picks; indexR++){
          for(indexI; indexI<amttomatch; indexI++){
             if (arrayRandom[indexR] != arrayInput[indexI]){
    			//printf("%d | %d\n", arrayRandom[indexR], arrayInput[indexI]);
                match = false;
    		 } else{
    			//printf("%d = %d\n", arrayRandom[indexR], arrayInput[indexI]); 
                amount++;
             }
          }
    	  //printf("match=%s\n", match ? "true" : "false");
    	  //printf("dup=%s\n", duplicate ? "true" : "false");
          indexI=0;
       }
      
       if(amount==amttomatch){
          match = true;  
       }
       //printf("%d | %d | ", amount, amttomatch);
       //printf("match=%s\n", match ? "true" : "false");
       return match;
    }
    
    /* Check an array while being created to prevent duplicate entries */
    bool checkArray(int currentIndex, int number, int array[]){
    	int index;
        for(index=0;index<=currentIndex;index++){
            if (array[index]==number){
    			//printf("%d = %d\n", array[index], number );
                return true;
            }
        }
        return false;
    }
    
    void print(int array[], int picks){
       int index = 0;
       puts("");
       for(index; index<picks; index++){
          printf("Number%d: %d\n",index+1,array[index]);
       }
    }
    
    void switch_print(double loop, double average, double DrawLoopCount, double draw_span){
       printf ("Attempts: %10.0lf  |  ", loop);
       printf ("Overall Average: %11.2lf  |  ", average);
       printf ("Draw Counter: %10.0lf  |  ", DrawLoopCount);
       printf ("Draw Span: %10.0lf  |  ", draw_span);
    }
    void printToFile(int array[], double loop, bool match, int picks, int amttomatch){
       int index = 0;
       FILE *fp2;
       //puts("");
       fp2 = fopen("matchAnyPartialAttempts.txt", "a");
       fprintf (fp2,"Attempts: %.0lf\n", loop);
       fprintf (fp2,"Match: %d\n", match);
       fprintf (fp2,"Match Picks: %2d\n", amttomatch);
       for(index; index<picks; index++){
    	  fprintf(fp2,"Number%d: %d\n",index+1,array[index]);
       }
       fprintf (fp2, "\n");
       fclose (fp2);
    }
    
    void sort( int array[], int picks){
        int index, temp, pass, limit;
        index = picks;
        limit = picks-2;
        for (pass=1;pass<=picks-1;++pass){
            for(index=0;index<=limit;++index){
                if (array[index]>array[index+1]){
                    temp=array[index];
                    array[index]=array[index+1];
                    array[index+1]=temp;
                }
            }
            --limit;
        }
    }
    
    int roll (int max) {
    	int rmax;
      	//rmax = rand()%max+1;
      	rmax = genrand64_int63()%max+1;
    	return rmax;
    }

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,626
    I haven't looked at your code, but remember that those odds (1 in 57) are for a match of 3 numbers in 6, so the user should still enter a ticket of 6 numbers. If any 3 of them match the generated number then they've matched 3. Since 6 choose 3 is 20, it's understandable that your probability is about 20 times too low.

    Here's a little program that gets the correct probabilities.
    Code:
    // gcc -std=c99 -Wall -W -pedantic -O3 lotto.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    #include <string.h>
     
    #define Reps     10000000
    #define MaxNums  49
    #define PickNums 6
     
    int main() {
        srand(time(NULL));
        int ticket[PickNums] = {1, 4, 15, 23, 39, 42}; // actually 2, 5, 16, etc.
        int match[PickNums + 1] = {0};
        int draw[MaxNums];
        for (int rep = 0; rep < Reps; ++rep) {
            //if (rep % 1000000 == 0) printf("%d\n", rep); // for long runs
            memset(draw, 0, MaxNums * sizeof *draw);
            for (int i = 0; i < PickNums; ) {
                int r = rand() % MaxNums;
                if (!draw[r]) {
                    draw[r] = 1;
                    ++i;
                }
            }
            int cnt = 0;
            for (int i = 0; i < PickNums; ++i)
                if (draw[ticket[i]])
                    ++cnt;
            ++match[cnt];
        }
        for (int i = 0; i <= PickNums; ++i)
            printf("%d. %10d %12.2f\n", i, match[i], (double)Reps / match[i]);
        return 0;
    }
    Output from a run of a hundred million reps:
    Code:
    0.   43597233         2.29
    1.   41302578         2.42
    2.   13239268         7.55
    3.    1762724        56.73
    4.      96336      1038.03
    5.       1854     53937.43
    6.          7  14285714.29
    Last edited by john.c; 03-14-2019 at 07:30 PM. Reason: named the constants
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    Nov 2004
    Posts
    6
    >>for a match of 3 numbers in 6, so the user should still enter a ticket of 6 numbers
    That is what I was missing. I was not making the other 3 possible numbers available to be checked for a match. I edited the code and now the probabilities for partial matches equal the calculated probability.

    Thanks john.c

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. no match for operator>> !?
    By Spyser in forum C++ Programming
    Replies: 2
    Last Post: 02-21-2012, 08:00 AM
  2. no match for operator =
    By vaibhavs17 in forum C++ Programming
    Replies: 4
    Last Post: 03-30-2009, 12:38 PM
  3. no match for 'operator>>'
    By Taka in forum C++ Programming
    Replies: 3
    Last Post: 03-30-2009, 12:17 AM
  4. Exact Match
    By pritin in forum C++ Programming
    Replies: 2
    Last Post: 03-26-2007, 08:50 AM
  5. 2 array match
    By ajastru2000 in forum C++ Programming
    Replies: 5
    Last Post: 07-18-2003, 07:58 AM

Tags for this Thread