Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::uniform_real_distribution inclusive range

Tags:

c++

random

c++11

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.

like image 763
Michael Marcin Avatar asked Apr 25 '13 20:04

Michael Marcin


2 Answers

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.

like image 191
Bill Avatar answered Oct 09 '22 07:10

Bill


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.

like image 32
bames53 Avatar answered Oct 09 '22 07:10

bames53