Random number generator, C++

后端 未结 8 2086
心在旅途
心在旅途 2020-12-10 18:25

I know there is a bit of limitations for a random number generation in C++ (can be non-uniform). How can I generate a number from 1 to 14620?

Thank you.

相关标签:
8条回答
  • 2020-12-10 18:32

    A common approach is to use std::rand() with a modulo:

    #include<cstdlib>
    #include<ctime>
    
    // ...
    std::srand(std::time(0));  // needed once per program run
    int r = std::rand() % 14620 + 1;
    

    However, as @tenfour mentions in his answer, the modulo operator can disrupt the uniformity of values std::rand() returns. This is because the modulo translates the values it discards into valid values, and this translation might not be uniform. For instance, for n in [0, 10) the value n % 9 translates 9 to 0, so you can get zero by either a true zero or a 9 translated to zero. The other values have each only one chance to yield.

    An alternative approach is to translate the random number from std::rand() to a floating-point value in the range [0, 1) and then translate and shift the value to within the range you desire.

    int r = static_cast<double>(std::rand()) / RAND_MAX * 14620) + 1;
    
    0 讨论(0)
  • 2020-12-10 18:42

    Use rand.

    ( rand() % 100 ) is in the range 0 to 99
    ( rand() % 100 + 1 ) is in the range 1 to 100
    ( rand() % 30 + 1985 ) is in the range 1985 to 2014
    
    ( rand() % 14620 + 1 ) is in the range 1 to 14620
    

    EDIT:

    As mentioned in the link, the randomizer should be seeded using srand before use. A common distinctive value to use is the result of a call to time.

    0 讨论(0)
  • 2020-12-10 18:43

    srand() / rand() are the functions you need, as others have answered.

    The problem with % is that the result is decidedly non-uniform. To illustrate, imagine that rand() returns a range of 0-3. Here are hypothetical results of calling it 4000 times:

    0 - 1000 times
    1 - 1000 times
    2 - 1000 times
    3 - 1000 times
    

    Now if you do the same sampling for (rand() % 3), you notice that the results would be like:

    0 - 2000 times
    1 - 1000 times
    2 - 1000 times
    

    Ouch! The more uniform solution is this:

    int n = (int)(((((double)std::rand()) / RAND_MAX) * 14620) + 1);

    Sorry for the sloppy code, but the idea is to scale it down properly to the range you want using floating point math, and convert to integer.

    0 讨论(0)
  • 2020-12-10 18:49

    The rand() function is not really the best Random generator, a better way would be by using CryptGenRandom().

    This example should do do the trick:

    #include <Windows.h>
    
    // Random-Generator
    HCRYPTPROV hProv;
    INT Random() {
        if (hProv == NULL) {
            if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_SILENT | CRYPT_VERIFYCONTEXT))
                ExitProcess(EXIT_FAILURE);
        }
    
        int out;
        CryptGenRandom(hProv, sizeof(out), (BYTE *)(&out));
        return out & 0x7fffffff;
    }
    
    int main() {
        int ri = Random() % 14620 + 1;
    }
    
    0 讨论(0)
  • 2020-12-10 18:52

    Here's a tutorial using the boost library http://www.boost.org/doc/libs/1_45_0/doc/html/boost_random/tutorial.html#boost_random.tutorial.generating_integers_in_a_range

    0 讨论(0)
  • 2020-12-10 18:55

    If you've got a c++0x environment, a close derivative of the boost lib is now standard:

    #include <random>
    #include <iostream>
    
    int main()
    {
        std::uniform_int_distribution<> d(1, 14620);
        std::mt19937 gen;
        std::cout << d(gen) << '\n';
    }
    

    This will be fast, easy and high quality.

    You didn't specify, but if you wanted floating point instead just sub in:

    std::uniform_real_distribution<> d(1, 14620);
    

    And if you needed a non-uniform distribution, you can build your own piece-wise constant or piece-wise linear distribution very easily.

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