0

I'm trying to use the random library. I know there's a similar question to this here: std::uniform_real_distribution inclusive range. From what I've read it should be [0, 10). I try to have [0, 10] but I've tried the solution and it doesn't work for me. I can't figure out why. Here's a bit of code.

std::vector<int> vec;

int main()
{   
    const int min = 0;
    const int max = 10;
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<> dis(min, std::nextafter(max, INT_MAX));
    const int MAX = 10; 
    for (int i = 0; i < MAX; i++)
    {
        int t = dis(gen);
        vec.push_back(t);
    }
    for (auto& i : vec)
        std::cout << i << std::endl;
    system("pause");
    return 0;
}

I've tried:

std::uniform_real_distribution<> dis(min, std::nextafter(max, INT_MAX));
std::uniform_real_distribution<> dis{ 0, 10 };
std::uniform_real_distribution<> dis(min, max);

It only produces 0 through 9 as random and doesn't include 10 like I want it to. I'm working on VS2013.

Community
  • 1
  • 1
pistachiobk
  • 304
  • 2
  • 15
  • real distribution should be some sort of floating point, not an integer. Getting up 9.99999 and never 10.0000 is a distinct possibility which will be truncated to 9 when stuffed into `int t` – user4581301 Sep 09 '15 at 19:19
  • 2
    Do you actually want `uniform_int_distribution`? The chance that a `uniform_real_distribution` on `[0, 10]` produces 10 is...very small. – T.C. Sep 09 '15 at 19:34
  • in other words: The thing you say you want is statistically indistinguishable from the thing you already have. – Chris Beck Sep 09 '15 at 20:22

1 Answers1

2

std::uniform_real_distribution works in Real numbers, not Integers. As a result is is very likely that the Real result of dis(gen); is getting truncated when it is stored in Integer int t. Because there are an infinite number of possible values available in the Real domain it is unlikely that exactly 10.0 with be returned in ten tries, and even if it did, floating point inaccuracy is likely to turn it into 9.999999 or similar.

This will show up as a float to int precision loss warning, if the compiler's warnings are turned on.

Quick solutions are

  1. Don't use int to store the returned value
  2. Use std::uniform_int_distribution instead of uniform_real_distribution.
Community
  • 1
  • 1
user4581301
  • 33,082
  • 7
  • 33
  • 54
  • I tried solution number one by storing my return value as a double but that didn't work. Solution number two works great. Thank you! – pistachiobk Sep 09 '15 at 20:48
  • I don't think FP inaccuracy turns 10.0 into 9.9999x as it's perfectly representable. Turning 10.0/3 into 3.33333 is the real problem, as 10.0/3 is not perfectly representable. – MSalters Sep 09 '15 at 20:58
  • @MSalters That's an interesting point. Have to check the math, but 10 is not being calculated and is a nice multiple of 2 so it sounds reasonable. – user4581301 Sep 09 '15 at 22:46
  • @user4581301: It's just 1.01 <<3. You need a 2 bits mantissa (leading 1 isn't stored). – MSalters Sep 09 '15 at 23:40