Random float number generation

后端 未结 14 1566
孤城傲影
孤城傲影 2020-11-22 05:05

How do I generate random floats in C++?

I thought I could take the integer rand and divide it by something, would that be adequate enough?

14条回答
  •  时光取名叫无心
    2020-11-22 05:39

    C++11 gives you a lot of new options with random. The canonical paper on this topic would be N3551, Random Number Generation in C++11

    To see why using rand() can be problematic see the rand() Considered Harmful presentation material by Stephan T. Lavavej given during the GoingNative 2013 event. The slides are in the comments but here is a direct link.

    I also cover boost as well as using rand since legacy code may still require its support.

    The example below is distilled from the cppreference site and uses the std::mersenne_twister_engine engine and the std::uniform_real_distribution which generates numbers in the [0,10) interval, with other engines and distributions commented out (see it live):

    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main()
    {
        std::random_device rd;
    
        //
        // Engines 
        //
        std::mt19937 e2(rd());
        //std::knuth_b e2(rd());
        //std::default_random_engine e2(rd()) ;
    
        //
        // Distribtuions
        //
        std::uniform_real_distribution<> dist(0, 10);
        //std::normal_distribution<> dist(2, 2);
        //std::student_t_distribution<> dist(5);
        //std::poisson_distribution<> dist(2);
        //std::extreme_value_distribution<> dist(0,2);
    
        std::map hist;
        for (int n = 0; n < 10000; ++n) {
            ++hist[std::floor(dist(e2))];
        }
    
        for (auto p : hist) {
            std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                      << p.first << ' ' << std::string(p.second/200, '*') << '\n';
        }
    }
    

    output will be similar to the following:

    0 ****
    1 ****
    2 ****
    3 ****
    4 *****
    5 ****
    6 *****
    7 ****
    8 *****
    9 ****
    

    The output will vary depending on which distribution you choose, so if we decided to go with std::normal_distribution with a value of 2 for both mean and stddev e.g. dist(2, 2) instead the output would be similar to this (see it live):

    -6 
    -5 
    -4 
    -3 
    -2 **
    -1 ****
     0 *******
     1 *********
     2 *********
     3 *******
     4 ****
     5 **
     6 
     7 
     8 
     9 
    

    The following is a modified version of some of the code presented in N3551 (see it live) :

    #include 
    #include 
    #include 
    #include 
    
    std::default_random_engine & global_urng( )
    {
        static std::default_random_engine u{};
        return u ;
    }
    
    void randomize( )
    {
        static std::random_device rd{};
        global_urng().seed( rd() );
    }
    
    int main( )
    {
      // Manufacture a deck of cards:
      using card = int;
      std::array deck{};
      std::iota(deck.begin(), deck.end(), 0);
    
      randomize( ) ;  
    
      std::shuffle(deck.begin(), deck.end(), global_urng());
      // Display each card in the shuffled deck:
      auto suit = []( card c ) { return "SHDC"[c / 13]; };
      auto rank = []( card c ) { return "AKQJT98765432"[c % 13]; };
    
      for( card c : deck )
          std::cout << ' ' << rank(c) << suit(c);
    
       std::cout << std::endl;
    }
    

    Results will look similar to:

    5H 5S AS 9S 4D 6H TH 6D KH 2S QS 9H 8H 3D KC TD 7H 2D KS 3C TC 7D 4C QH QC QD JD AH JC AC KD 9D 5C 2H 4H 9C 8C JH 5D 4S 7C AD 3S 8S TS 2C 8D 3H 6C JS 7S 6S

    Boost

    Of course Boost.Random is always an option as well, here I am using boost::random::uniform_real_distribution:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main()
    {
        boost::random::mt19937 gen;
        boost::random::uniform_real_distribution<> dist(0, 10);
    
        std::map hist;
        for (int n = 0; n < 10000; ++n) {
            ++hist[std::floor(dist(gen))];
        }
    
        for (auto p : hist) {
            std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                      << p.first << ' ' << std::string(p.second/200, '*') << '\n';
        }
    }
    

    rand()

    If you must use rand() then we can go to the C FAQ for a guides on How can I generate floating-point random numbers? , which basically gives an example similar to this for generating an on the interval [0,1):

    #include 
    
    double randZeroToOne()
    {
        return rand() / (RAND_MAX + 1.);
    }
    

    and to generate a random number in the range from [M,N):

    double randMToN(double M, double N)
    {
        return M + (rand() / ( RAND_MAX / (N-M) ) ) ;  
    }
    

提交回复
热议问题