Uniformity of random numbers taken modulo N

前端 未结 4 1208
北海茫月
北海茫月 2020-12-01 18:48

One common way of choosing a random number in [0, n) is to take the result of rand() modulo n: rand() % n. However, even if the r

相关标签:
4条回答
  • 2020-12-01 18:57

    There are two problems with using remainder (% is not a "modulo" operator in C) to a uniform random number over a reduced range. First is that there is a slight bias toward smaller numbers (mentioned above) and second that typical PRNGs tend to be less random in the low order bits. I seem to recall that from Knuth (The Art of Computer Programming, Vol II, Seminumerical Algorithms) along with the claim that (after translating from MIX to C) rand()%2 is a poor source of random single bits. It's better to pick (rand() > RAND_MAX/2) (or test a high-order bit, if RAND_MAX is nearly a power of 2.)

    The remainder should be good enough casual use on small intervals. Avoid it for simulations. Actually, avoid rand() altogether for large simulations or "Monte Carlo" computations. Implementations tend to have a period on the order of 2^32 or less. It's not hard to exceed 4 billion trials on a 2+ GHz processor.

    0 讨论(0)
  • 2020-12-01 19:03

    That depends on:

    • The value of RAND_MAX
    • Your value of N

    Let us assume your RAND_MAX is 2^32. If N is rather small (let's say 2) then the bias is 1 / 2^31 -- or too small to notice.

    But if N is quite a bit larger, say 2^20, then the bias is 1 / 2^12, or about 1 in 4096. A lot bigger, but still pretty small.

    0 讨论(0)
  • 2020-12-01 19:04

    One approach you can do is the following:

    Knowing the value of N, you make R_MAX = ((RAND_MAX + 1) / N) * N; for uniformity.

    So you can do your custom rand() function:

    int custom_rand(int mod) {
        int x = rand();
        const int R_MAX = ((RAND_MAX + 1) / mod) * mod;    
    
        while (x > R_MAX) { // discard the result if it is bigger
            x = rand();
        }
    
        return (x % mod);
    }
    
    0 讨论(0)
  • 2020-12-01 19:16

    You are correct, rand() % N is not precisely uniformly distributed. Precisely how much that matters depends on the range of numbers you want and the degree of randomness you want, but if you want enough randomness that you'd even care about it you don't want to use rand() anyway. Get a real random number generator.

    That said, to get a real random distribution, mod to the next power of 2 and sample until you get one in the range you want (e.g. for 0-9, use while(n = rand()%0x10 > 10);).

    0 讨论(0)
提交回复
热议问题