Random number from normal distribution in C++

前端 未结 2 1015
谎友^
谎友^ 2021-01-19 17:02

As a complete beginner to C++, I would like to generate a random number from a normal distribution.

With the following code (derived from this post), I am able to d

2条回答
  •  隐瞒了意图╮
    2021-01-19 17:38

    (1) Why is that happing and how do I fix this?

    It's happening because you default construct your PRNG (pseudo random number generator) and don't seed it. A PRNG generates a deterministic sequence of numbers. The sequence is typically very long and then it starts all over again. The seed is used to set the internal state of the PRNG - its starting point so to speak. Given no seed, it'll start with the same state every time.

    (2) Is there another easier way to generate random numbers?

    No, not using modern standard C++ (C++11 and later).

    Some notes:

    • Using a time based seed based on a one-shot sample of the clock is considered bad since you risk seeding two PRNG:s with the same value.
    • You only need one PRNG (per thread that needs to generate random numbers) in you program - and seeding a PRNG is considered costly (in terms of speed). You could therefore make the generator global so it can be used everywhere in the program. The below is a thread safe version, initialized with what is supposed to be a True (but slow) RNG, generating numbers from an entropy pool, std::random_device.
      std::mt19937& prng() {           // extern declared in a header file
          static thread_local std::mt19937 gen(std::random_device{}());
          return gen;
      }
      
    • If your random_device lacks entropy or is buggy (older versions of MinGW had a buggy implementation) you can combine random_device output with a few time based numbers (sampled some time apart) to create a std::seed_seq that you use to initialize your PRNG. The below should work with both buggy and conformant implementations to create a seed that is hard to predict:

      #include 
      #include 
      
      // Create a seed_seq with 2 time based numbers and 2 random_device numbers.
      // The two sleeps are done to ensure some diff in the clock counts.
      static std::seed_seq get_seed() {
          static constexpr auto min = std::chrono::steady_clock::duration::min();
          std::random_device rd;
          std::uint_least32_t si[4];
          for(size_t s = 0; s < std::size(si);) {
              si[s++] = rd();
              std::this_thread::sleep_for(min);
              si[s++] = static_cast(
                  std::chrono::steady_clock::now().time_since_epoch().count());
              std::this_thread::sleep_for(min);
          }
          return {si[0], si[1], si[2], si[3]};
      }
      
      std::mt19937& prng() {           // extern declared in a header file
          static thread_local std::seed_seq seed = get_seed();
          static thread_local std::mt19937 gen(seed);
          return gen;
      }
      

提交回复
热议问题