How to use to replace rand()?

后端 未结 5 816
执笔经年
执笔经年 2020-12-28 13:45

C++11 introduced the header with declarations for random number engines and random distributions. That\'s great - time to replace those uses of <

5条回答
  •  遥遥无期
    2020-12-28 14:11

    Assuming you want the behavior of the C-style rand and srand functions, including their quirkiness, but with good random, this is the closest I could get.

    #include 
    #include   // RAND_MAX  (might be removed soon?)
    #include   // INT_MAX   (use as replacement?)
    
    
    namespace replacement
    {
    
      constexpr int rand_max {
    #ifdef RAND_MAX
          RAND_MAX
    #else
          INT_MAX
    #endif
      };
    
      namespace detail
      {
    
        inline std::default_random_engine&
        get_engine() noexcept
        {
          // Seeding with 1 is silly, but required behavior
          static thread_local auto rndeng = std::default_random_engine(1);
          return rndeng;
        }
    
        inline std::uniform_int_distribution&
        get_distribution() noexcept
        {
          static thread_local auto rnddst = std::uniform_int_distribution {0, rand_max};
          return rnddst;
        }
    
      }  // namespace detail
    
      inline int
      rand() noexcept
      {
        return detail::get_distribution()(detail::get_engine());
      }
    
      inline void
      srand(const unsigned seed) noexcept
      {
        detail::get_engine().seed(seed);
        detail::get_distribution().reset();
      }
    
      inline void
      srand()
      {
        std::random_device rnddev {};
        srand(rnddev());
      }
    
    }  // namespace replacement
    

    The replacement::* functions can be used exactly like their std::* counterparts from . I have added a srand overload that takes no arguments and seeds the engine with a “real” random number obtained from a std::random_device. How “real” that randomness will be is of course implementation defined.

    The engine and the distribution are held as thread_local static instances so they carry state across multiple calls but still allow different threads to observe predictable sequences. (It's also a performance gain because you don't need to re-construct the engine or use locks and potentially trash other people's cashes.)

    I've used std::default_random_engine because you did but I don't like it very much. The Mersenne Twister engines (std::mt19937 and std::mt19937_64) produce much better “randomness” and, surprisingly, have also been observed to be faster. I don't think that any compliant program must rely on std::rand being implemented using any specific kind of pseudo random engine. (And even if it did, implementations are free to define std::default_random_engine to whatever they like so you'd have to use something like std::minstd_rand to be sure.)

提交回复
热议问题