std::uniform_real_distribution inclusive range

2019-02-09 05:52发布

问题:

C++11 std::uniform_real_distribution( -1, 1 ) gives numbers in the range [-1,1).

How would you get a uniform real distribution in the range [-1,1]?

Practically it probably doesn't matter but logically I'm trying to select a value in the inclusive range.

回答1:

This is easier to think about if you start by looking at integers. If you pass [-1, 1) you would expect to get -1, 0. Since you want to include 1, you would pass [-1, (1+1)), or [-1, 2). Now you get -1, 0, 1.

You want to do the same thing, but with doubles:

Borrowing from this answer:

#include <cfloat> // DBL_MAX
#include <cmath> // std::nextafter
#include <random>
#include <iostream>

int main()
{
  const double start = -1.0;
  const double stop = 1.0;

  std::random_device rd;
  std::mt19937 gen(rd());

  // Note: uniform_real_distribution does [start, stop),
  //   but we want to do [start, stop].
  //   Pass the next largest value instead.
  std::uniform_real_distribution<> dis(start, std::nextafter(stop, DBL_MAX));

  for (auto i = 0; i < 100; ++i)
  {
    std::cout << dis(gen) << "\n";
  }
  std::cout << std::endl;
}

(See the code run here)

That is, find the next largest double value after the one you want, and pass that as the end value instead.



回答2:

Unfortunately the actual implementations of the floating point distributions don't allow you to be so precise. E.g., uniform_real_distribution<float> is supposed to produce values in a given half range, but due to rounding issues it may in fact produce values in an inclusive range instead.

Here's an example of the problem with generate_cannonical, and similar problems occur with the other real_distributions.



标签: c++ random c++11