Why does C++ rand() seem to generate only numbers of the same order of magnitude?

前端 未结 9 2064
孤独总比滥情好
孤独总比滥情好 2021-01-30 01:14

In a small application written in C/C++, I am facing a problem with the rand function and maybe the seed :

I want to produce a sequence of random numbers th

相关标签:
9条回答
  • 2021-01-30 01:52

    There are exactly equal number of numbers between 0 and 2^29 and 2^29 and 2^30.

    Another way of looking at the problem: consider binary representation of the random number you generate, the probability that the highest bit is 1 equals 1/2, and, therefore, you get order 29 in half cases. What you want is to see a number that would be below 2^25, but that means 5 highest bits are all zero, which happens with a low probability of 1/32. Chances are that even if you run it for a long time you will never see the order below 15 at all (the probability is something like rolling 6 6 times in a row).

    Now, the part of your question about the seed. No, the seed cannot possibly determine the range the numbers are generated from, it just determines the first, initial element. Think of rand() as a sequence of all possible numbers in the range (predetermined permutation). The seed determines where you start drawing numbers from the sequence. This is why if you want (pseudo) randomness, you use current time to initialize the sequence: you do not care that the position you start from is not uniformly distributed, all that matters is that you never start from the same position.

    0 讨论(0)
  • 2021-01-30 02:01

    @C4stor made a great point. But, for a more general case and easier to understand for human (base 10): for the range from 1 to 10^n, ~90% of the numbers are from 10^(n-1) to 10^n, therefore, ~99% of the numbers go from 10^(n-2) to 10^n. Keep adding as many decimals as you want.

    Funny mathematics, if you keep doing this for n, you can see that from 1 to 10^n, 99.9999...% = 100% of the numbers are from 10^0 to 10^n with this method.

    Now about code, if you want a random number with random orders of magnitude, from 0 to 10^n, you could do:

    1. Generate a small random number from 0 to n

    2. If you know the range that n has, generate a big random number of order 10^k where k > max{n}.

    3. Cut the longer random number to get the n digits of this big random number.

    0 讨论(0)
  • 2021-01-30 02:02

    The basic (and correct) answer was already given and accepted above: there are 10 numbers between 0 and 9, 90 numbers between 10 and 99, 900 between 100 and 999, etc.

    For a computationally efficient way to get a distribution with approximately logarithmic distribution, you want to right-shift your random number by a random number:

    s = rand() & 31; // a random number between 0 and 31 inclusive, assuming RAND_MAX = 2^32-1
    r = rand() >> s; // right shift
    

    It's not perfect, but it's much faster than computing pow(2, rand()*scalefactor). It will be "lumpy" in the sense that the distribution will be uniform for numbers within a factor 2 (uniform for 128 to 255, half the density for 256 to 1023, etc).

    Here is a histogram of the frequency of the numbers 0 to 31 (in 1M samples):

    enter image description here

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