10

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.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
Michael Marcin
  • 686
  • 6
  • 17

2 Answers2

21

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.

Community
  • 1
  • 1
Bill
  • 14,257
  • 4
  • 43
  • 55
  • 1
    Wonderful, thank you. VS2012 doesn't appear to have this function but luckily boost has it in [math toolkit](http://www.boost.org/doc/libs/1_53_0/libs/math/doc/sf_and_dist/html/math_toolkit/utils/next_float/nextafter.html) – Michael Marcin Apr 25 '13 at 23:06
  • The standard floating point distributions do not provide accuracy down to the last digit of precision, but instead suffer from rounding issues that mean it's not appropriate to try to use them in this way. – bames53 Dec 08 '15 at 21:57
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.

Community
  • 1
  • 1
bames53
  • 86,085
  • 15
  • 179
  • 244