How to generate a random integer number from within a range

后端 未结 11 1242
隐瞒了意图╮
隐瞒了意图╮ 2020-11-21 23:57

This is a follow on from a previously posted question:

How to generate a random number in C?

I wish to be able to generate a random number from within a part

11条回答
  •  花落未央
    2020-11-22 00:40

    While Ryan is correct, the solution can be much simpler based on what is known about the source of the randomness. To re-state the problem:

    • There is a source of randomness, outputting integer numbers in range [0, MAX) with uniform distribution.
    • The goal is to produce uniformly distributed random integer numbers in range [rmin, rmax] where 0 <= rmin < rmax < MAX.

    In my experience, if the number of bins (or "boxes") is significantly smaller than the range of the original numbers, and the original source is cryptographically strong - there is no need to go through all that rigamarole, and simple modulo division would suffice (like output = rnd.next() % (rmax+1), if rmin == 0), and produce random numbers that are distributed uniformly "enough", and without any loss of speed. The key factor is the randomness source (i.e., kids, don't try this at home with rand()).

    Here's an example/proof of how it works in practice. I wanted to generate random numbers from 1 to 22, having a cryptographically strong source that produced random bytes (based on Intel RDRAND). The results are:

    Rnd distribution test (22 boxes, numbers of entries in each box):     
     1: 409443    4.55%
     2: 408736    4.54%
     3: 408557    4.54%
     4: 409125    4.55%
     5: 408812    4.54%
     6: 409418    4.55%
     7: 408365    4.54%
     8: 407992    4.53%
     9: 409262    4.55%
    10: 408112    4.53%
    11: 409995    4.56%
    12: 409810    4.55%
    13: 409638    4.55%
    14: 408905    4.54%
    15: 408484    4.54%
    16: 408211    4.54%
    17: 409773    4.55%
    18: 409597    4.55%
    19: 409727    4.55%
    20: 409062    4.55%
    21: 409634    4.55%
    22: 409342    4.55%   
    total: 100.00%
    

    This is as close to uniform as I need for my purpose (fair dice throw, generating cryptographically strong codebooks for WWII cipher machines such as http://users.telenet.be/d.rijmenants/en/kl-7sim.htm, etc). The output does not show any appreciable bias.

    Here's the source of cryptographically strong (true) random number generator: Intel Digital Random Number Generator and a sample code that produces 64-bit (unsigned) random numbers.

    int rdrand64_step(unsigned long long int *therand)
    {
      unsigned long long int foo;
      int cf_error_status;
    
      asm("rdrand %%rax; \
            mov $1,%%edx; \
            cmovae %%rax,%%rdx; \
            mov %%edx,%1; \
            mov %%rax, %0;":"=r"(foo),"=r"(cf_error_status)::"%rax","%rdx");
            *therand = foo;
      return cf_error_status;
    }
    

    I compiled it on Mac OS X with clang-6.0.1 (straight), and with gcc-4.8.3 using "-Wa,q" flag (because GAS does not support these new instructions).

提交回复
热议问题