Thread: Lottery Simulation

  1. #1
    Registered User
    Join Date
    Feb 2019
    Posts
    4

    Lottery Simulation

    for my university assignment i have been asked to create a lottery simulation program.

    the program needs to:
    1. Welcome user to the program
    2. Store 6 original numbers (saved in the code)
    3. Ask how many years to simulate
    4. Generate 6 unique lottery numbers (between 1-49)
    5. Check the original numbers against lottery numbers
    6. Store number of lottery numbers matched
    7. Repeat step 4-6 for X years, or until jackpot is won.
    Print year and results.

    i have also attached a picture of a basis of what i want the program to look like.
    Lottery Simulation-screen-shot-2019-03-20-20-14-11-png
    im not asking for someone to write this code for me just give me some ideas on what i will need to use in my code to make this program.

    Many Thanks
    Last edited by TheRealfawcett; 03-20-2019 at 02:15 PM.

  2. #2
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,728
    Ok, the obvious way is to have an array of numbers from 1 to 49 which you would shuffle, and then maybe pick the first 6 or the last 6 or whatever.

    The shuffling can be made in a variety of ways, the easier one being to swap the position of two numbers in random positions for at least 100 times. The more numbers you swap, the more shuffled the array will be in the end. Practically, this can be accomplished by generating two random indices between 0 to 48, kinda like this:
    Code:
    int index1 = rand() % 49;
    int index2 = rand() % 49;
    
    int temp = randArray[index1];
    randArray[index1] = randArray[index2];
    randArray[index2] = temp;
    put that inside a for loop and you're golden.

    EDIT: I should point out that the previous method of generating ranged random numbers isn't very good, because PRNGs typically have some bias in their least significant bits. If you're interested, you might want to look into this alternative method:
    Code:
    int index = (int)((rand()/(double)RAND_MAX)*48 + 0.5);
    Oh, and don't forget to use srand(time(NULL)) somewhere at the beginning of your program. Use it only once.
    Last edited by GReaper; 03-20-2019 at 03:18 PM.
    Devoted my life to programming...

  3. #3
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,148
    Quote Originally Posted by GReaper
    The shuffling can be made in a variety of ways, the easier one being to swap the position of two numbers in random positions for at least 100 times. The more numbers you swap, the more shuffled the array will be in the end. Practically, this can be accomplished by generating two random indices between 0 to 48
    Instead of that, I'd suggest Knuth shuffle (a.k.a. Fisher-Yates shuffle): for each element in the array, pick a random element in the range from the element to the end (or beginning, if you iterate in reverse), then swap them.

    That said, with only 6 numbers out of a possible 49, shuffling an array just to select the first 12% of the elements is a bit of a waste. I'd suggest generating 6 random numbers in the range, re-generating if you generate a duplicate
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  4. #4
    TEIAM - problem solved
    Join Date
    Apr 2012
    Location
    Melbourne Australia
    Posts
    1,859
    A good place to start is here - FAQ > Generate random numbers? - Cprogramming.com

    I'd suggest that you start with laserlight's second suggestion with an array of 6, re-generating if you generate a duplicate.
    Fact - Beethoven wrote his first symphony in C

  5. #5
    Registered User
    Join Date
    Feb 2019
    Posts
    533
    Some considerations about random numbers generation. GReaper is right pointing to the fact that the linear congruential random number generator is problematic. The lower bits tends to be less random. Notice that this is a characteristic of this specific PRNG and the method using floating-point is a way to mitigate the problem obtaining a value between 0.0 and 1.0, and multiplying by the desired range. But there is a faster way: Use the upper bits instead.

    This expression:
    Code:
    int index = (int)((rand()/(double)RAND_MAX)*48 + 0.5);
    Could be writen using, entirely, integer operations like:
    Code:
    int index = (rand() >> 25) % 50;
    Why 25 bits right shift? Because we need values between 0 and 2⁶ (64, the upper 6 bits -- more bits will be less random!), but rand() always returns an unsigned value (it is usual RAND_MAX to have the most significant bit zeroed). And for i386 and x86-64 modes it is usual RAND_MAX to be 31 bits long...

    The second function is faster the the first (no floating point required and just one division)...

    Hardware RNG:

    There is a faster way, and more random!

    If you are using Intel or AMD processors and want a "truly random" number (not "pseudo"), Modern architectures (since Haswell, for instance) has an internal diode to measure "noise" caused by temperature. Using this "quantum effect" we have a "true" RNG (almost!). And there is an instruction to get these random values generated by the CPU: RDRAND.

    There are two advantages: RDRAND is faster then rand() and will return 16, 32 or 64 bits of truly random number (not 31).

    Except by the intrinsic function __cpuid(), I prefer to implement RDRAND in assembly (there is an instrinsic __randNN_step() available in immintrin.h). NN is 16, 32 or 64:

    Code:
    #include <stdlib.h>
    #include <time.h>
    
    #if defined( __x86_64__ ) || defined( __i386__ )
    #include <cpuid.h>
    
    static int supports_rdrand = 0;
    
    // This will be called before main()...
    __attribute__ ( ( constructor ) )
    void test_rdrand_support ( void )
    {
    # ifdef __x86_64__
      unsigned long long flags;
    # else
      unsigned int flags;
    # endif
      unsigned int a, b, c, d;
    
      __asm__ __volatile__ (
    # ifdef __x86_64__
        "pushfq; popq %0"
    # else
        "pushfl; popl %0"
    # endif
        : "=g" ( flags ) );
    
      // supports cpuid?
      supports_rand = 0;
      if ( flags & ( 1U << 21 ) )
        supports_rdrand = 1;
    
      if ( supports_rdrand )
      {
        __cpuid ( 1, a, b, c, d );
        supports_rdrand = !! ( c & ( 1U << 30 ) );
    
        if ( supports_rand )
          return;
      }
    
      srand ( time ( NULL ) );
    }
    
    int getrand ( void )
    {
      if ( supports_rdrand )
      {
        int rnd;
    
        __asm__ __volatile__ (
          "1: rdrand %0; jnc 1b" : "=r" ( rnd )
        );
    
        return rnd;
      }
      else
        return rand();
    }
    #else
    # define getrand(...) rand()
    #endif
    Last edited by flp1969; 03-20-2019 at 05:05 PM.

  6. #6
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    27,148
    Quote Originally Posted by flp1969
    Notice that this is a characteristic of this specific PRNG
    Exactly, and what algorithm is chosen for rand() is implementation defined. If I needed a quality PRNG, I would drop in a known PRNG implementation rather than try and guess what problems rand() might present. For a university assignment that clearly is a throwaway learning program in which the specifics of the PRNG or RNG isn't the learning point, nah. Just use rand() % n and investigate PRNGs and RNGs outside of the assignment confines.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  7. #7
    Registered User
    Join Date
    Dec 2017
    Posts
    630
    @flp, That jnc 1b looks a little fishy to me. Maybe I'm wrong, but doesn't that translate as "if the carry flag is not set (i.e., if rdrand failed) then jump forward 27 bytes?
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  8. #8
    Registered User
    Join Date
    Feb 2019
    Posts
    533
    Quote Originally Posted by john.c View Post
    @flp, That jnc 1b looks a little fishy to me. Maybe I'm wrong, but doesn't that translate as "if the carry flag is not set (i.e., if rdrand failed) then jump forward 27 bytes?
    Hehehe... it looks that way! I was confused when I saw this for the first time, but assembly in AT&T sintax requires a suffix 'f' (forward) or 'b' (backward) when the label is numeric:
    Code:
    1:
      rdrand
      jnc 1b     # jumps to 1 (backwards)
      jmp 1f    # jumps to 1 (forward)
    1:
    To use a hexadecimal value you need to prefix with '0x' (or, maybe, '$0x' - must test).
    Last edited by flp1969; 03-21-2019 at 04:04 AM.

  9. #9
    Registered User
    Join Date
    Feb 2019
    Posts
    533
    Ahhh... and this piece of asm is not entirely correct (it works!). The correct approach should be:

    Code:
    __asm__ __volatile__ ( "1: rdrand %0; jnc 1b" : "=r" (rnd) :: "cc" );
    Because rdrand mess with the carry flag. The "cc" in "clobbered" field of asm block says to the compiler: "preserve the flags, if you must".

    PS: Usually I prefer not to use ';' as a separator (for Intel processors, GNU Assembler uses # as comments). I wrote this way as a one liner. The syntax I prefer is:
    Code:
    __asm__ __volatile__ (
      "1:\t\n"
      "  rdrand %0\t\n"
      "  jnc 1b\t\n"
    : "=r" (rnd) : : "cc" );
    This way, when creating an asm listing with -S on GCC, this piece of code will be perfectly aligned with the remaining code...
    Last edited by flp1969; 03-21-2019 at 04:19 AM.

  10. #10
    Registered User
    Join Date
    Feb 2019
    Posts
    533
    A useful manual for those interested on assembly, AT&T syntax for Intel instruction set:
    Sun's AT&T Assembly Syntax Manual.

  11. #11
    Registered User
    Join Date
    Dec 2017
    Posts
    630
    @flp, If it means jump 1 byte backwards then it needs to be more than 1. The program counter will point to the beginning of the instruction after the jnc instruction, so you need to jump back as many bytes in both the jnc and the rdrand (and even the rdrand will be more than 1 byte long). It probably seems to work simply because rdrand rarely fails. Technically you shouldn't just jump back to it in an potentially infinite loop, but should instead retry it a fixed number of times. Intel recommends 10 times. Intel(R) Digital Random Number Generator (DRNG) Software Implementation Guide | Intel(R) Software
    Last edited by john.c; 03-21-2019 at 09:02 AM.
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  12. #12
    Registered User
    Join Date
    Feb 2019
    Posts
    533
    Quote Originally Posted by john.c View Post
    @flp, If it means jump 1 byte backwards then it needs to be more than 1
    No... it means jump to the label '1' before this point. Note, in the other example, there are 2 labels '1'...

    I know the meaning of relative to RIP (or EIP) jumps...
    In AT&T Syntax you can use numeric labels this way...

    Code:
    1: jmp 1f   # jumps to "jmp 2b".
    2: jmp 2f   # jumps to "jmp 1b"
    1: jmp 2b  # jumps to "jmp 2f"
    2: jmp 1b  # jumps to "jmp 2b"
    It's like the Knuth MIX assembly language!

    And this example, using RDRAND, isn't an infinite loop... RDRAND will set CF when all "random" bits are available... CF=0 (and the destination is 0) when RDRAND still don't have them all...
    Last edited by flp1969; 03-21-2019 at 09:29 AM.

  13. #13
    Registered User
    Join Date
    Dec 2017
    Posts
    630
    Oh, of course. The 1 is a label. That makes sense now.

    But I didn't say it was an infinite loop. I said it could become one if rdrand was for some reason not working properly. I also pointed you to the Intel documentation that recommends retrying only 10 times then giving up.
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  14. #14
    Registered User
    Join Date
    Feb 2019
    Posts
    533
    @john.c, here is a non-sense function to demonstrate:

    Code:
    # test.s
    .globl f
    f:
    1:
      jmp 2f
    2:
      jmp 1b
      jmp 1f
      nop
    1:
      hlt
    Compiling and getiing the generated code:
    Code:
    $ as -o test.o test.s
    $ objdump -dM intel test.o
    objdump -dM intel test.o
    
    test.o:     file format elf64-x86-64
    
    Disassembly of section .text:
    
    0000000000000000 <f>:
       0:    eb 00                    jmp    2 <f+0x2>
       2:    eb fc                    jmp    0 <f>
       4:    eb 01                    jmp    7 <f+0x7>
       6:    90                       nop
       7:    f4                       hlt

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Lottery - C Programm
    By Gooody in forum C Programming
    Replies: 6
    Last Post: 12-11-2014, 09:40 AM
  2. Need help with my lottery game
    By Elina Sumin in forum C Programming
    Replies: 8
    Last Post: 11-27-2014, 03:57 PM
  3. Need help with my lottery game
    By Elina Sumin in forum C Programming
    Replies: 1
    Last Post: 11-27-2014, 03:10 PM
  4. Lottery game
    By got1sleeve in forum C++ Programming
    Replies: 3
    Last Post: 02-16-2008, 01:55 PM
  5. Yet another lottery program
    By BungleSpice in forum C Programming
    Replies: 10
    Last Post: 04-01-2004, 02:08 PM

Tags for this Thread