5

Notes:

  1. My compiler is g++ 5.1.0-2 with c++14 language standards
  2. My IDE is Code::Blocks (I tried the code on Dev-C++ too)
  3. The online IDEs I tested the code on were http://cpp.sh/ (C++ shell) and https://www.codechef.com/ide (CodeChef.com's IDE) both running c++14
  4. The code runs ok when using an online IDE, which puzzles me even more.

Here is the code:

#include <iostream>
#include <random>
#include <cstdlib>
#include <ctime>
#include <chrono>

int main() {
    srand(time(0));
    long long seed = rand();
    std::default_random_engine rand_num(seed);
    std::uniform_int_distribution<long long> range(0, 10);
    long long a = range(rand_num);
    long long b = rand_num();
    std::cout<<seed<<"\n"; // the seed is different every time (tested)
    std::cout<<a<<"\n";
    std::cout<<b<<"\n";
    system("pause");
    return 0;
}

The one with std::uniform_int_distribution (a) isn't random when running the code on my own computer but works ok and creates a random number on the online IDEs.

The one without std::uniform_int_distribution (b) works ok with both online IDEs and my own computer.

What's the problem? How can I fix it?

UPDATE: The code works ok with mt19937 engine (std::mt19937 and std::mt19937_64)

gagan mahatma
  • 336
  • 2
  • 9
  • 2
    Did you try to print `seed` and the result of the call to `time(0)`, to see the origin of the non-randomness? – Pixelchemist Jan 08 '16 at 16:13
  • 1
    @Pixelchemist Yes, the seed was different every time. (Added the info to the question) –  Jan 08 '16 at 16:21
  • Ok, did you test multiple runs when printing a whole sequence? (`for(unisgned i=0; i<10; ++i) { std::cout << range(rand_num) << ' '; }`) – Pixelchemist Jan 08 '16 at 16:26
  • @Pixelchemist Yes. In fact, I discovered the problem when creating a random array with a for loop. –  Jan 08 '16 at 16:30
  • I tested it with gcc 4.8/c++11 and it worked as supposed. Looks like a bug in the implementation of the specific stl version. Can you specify the gcc version more precisely? The version number 5.10-2 does not exist on gcc.gnu.org. – MarkusParker Jan 08 '16 at 16:31
  • @MarkusParker It's 5.1.0-2. That's what the installer says. I can only see 5.1.0 in the release notes –  Jan 08 '16 at 16:35
  • I could not reproduce the issue with gcc 5.2.0 or gcc 4.9.3 either. Maybe the answer described in http://htmlasks.com/_lt_randomgt_generates_same_number_in_linux_but_not_in_windows helps? – MarkusParker Jan 08 '16 at 16:49
  • MinGW's `rand` is Microsoft's, which is pretty terrible. The algorithm used means that increasing the seed by 1 usually results in the output differing by 3. You use that to seed the `default_random_engine`, and then [this issue](http://stackoverflow.com/questions/32730906/random-generates-same-number-in-linux-but-not-in-windows) kicks in. – T.C. Jan 08 '16 at 18:19
  • @MarkusParker "_specific stl version_" The STL has nothing to do with any PRNG. – curiousguy Jul 03 '18 at 16:01

2 Answers2

4

It seems to be a known problem of g++ implementation on Windows. See the accepted answer to a similar question: Why do I get the same sequence for every run with std::random_device with mingw gcc4.8.1?

To avoid the problem you can use <chrono> facilities to seed the random number generator:

#include <iostream>
#include <random>
#include <cstdlib>
#include <ctime>
#include <chrono>

int main() {
    srand(time(0));
    long long seed = rand();

    std::default_random_engine rand_num{static_cast<long unsigned int>(std::chrono::high_resolution_clock::now().time_since_epoch().count())};
    //                                  ^ ^ ^ ^ ^ ^^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^ ^
    std::uniform_int_distribution<long long> range{1,10};

    long long a = range(rand_num);
    long long b = rand_num();
    std::cout<<seed<<"\n"; // the seed is different every time (tested)
    std::cout<<a<<"\n";
    std::cout<<b<<"\n";
    system("pause");
    return 0;
}

This gave me different results at every run ( with g++ on Windows).

Community
  • 1
  • 1
Bob__
  • 12,361
  • 3
  • 28
  • 42
  • As I mentioned in the update, it works ok with mt19937 engine –  Jan 08 '16 at 17:41
  • @SalehShamloo Sorry, I've updated the answer using `std::default_random_engine`. It works, in my environment. – Bob__ Jan 08 '16 at 17:54
  • It works. Thank you. But i'm getting the same results when I put it in a `for` loop. They are different in each run, but not different from other numbers produced in the `for` loop. –  Jan 08 '16 at 18:10
  • What do you mean? `for ( int i=0; i<16; i++) { std::cout << range(rand_num) << '\n'; }` works fine for me... – Bob__ Jan 08 '16 at 18:16
  • Sorry, my bad. Anyway, Thank you for your answer. It was very helpful. –  Jan 08 '16 at 18:27
1

Your code works fine with Visual C++, but fails for me with g++ 5.2.0. It looks to me like a bug in gcc's standard library.

Yet more evidence that using the default_random_engine is just a bad idea in general, and using time(0) as a seed is pretty awful as well (though a quick check indicates that changing it to use random_device for the seed still produces broken results).

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • I'd expect `default_random_engine` to be an alias to another predefined RNE which when specifically selected would exhibit the same problem. – Pixelchemist Jan 08 '16 at 16:43
  • 1
    `random_device` actually always generates the same seed for me in every run. I'm using Mingw-W64(gcc 4.9.1) – Not a real meerkat Jan 08 '16 at 16:43
  • @Jerry Thank you for the answer. I used `time(0)` because `random_device` gives the same results every time. –  Jan 08 '16 at 16:44
  • 1
    I think it is strange that it does not work in `5.1.0-2` and `5.2.0` but in between [ideone (using `__VERSION__ == 5.1.1 20150711`)] it does. – Pixelchemist Jan 08 '16 at 16:51
  • 1
    @Pixelchemist: This is a library problem, so the question would be what *library* the compiler's using online. If they're using `libc++` (for the obvious alternative), that would explain a lot. Oh, but `random_device` shouldn't give the same result every time--are you sure you invoked it correctly? It's a class, so to invoke it without defining an object, you need to use `random_device()()`. – Jerry Coffin Jan 08 '16 at 16:54
  • @JerryCoffin Nope. Still same results with `random_device`. –  Jan 08 '16 at 17:01
  • @SalehShamloo: Just to be sure I understand what you're saying: do you mean the `a` output remains the same even when using `random_device` (which is as I've said above) or that the result from invoking `random_device` itself remains constant? – Jerry Coffin Jan 08 '16 at 17:04
  • 1
    `random_device` always gives the same sequence in MinGW, or at least it did: http://stackoverflow.com/q/18880654/10077 – Fred Larson Jan 08 '16 at 17:06
  • @JerryCoffin Both statements are true. –  Jan 08 '16 at 17:07
  • Ok, I'm downloading gcc 5.3.0-1. with my crappy internet connection, it will take a while. I will update the post when I'm done. –  Jan 08 '16 at 17:10
  • @SalehShamloo: If the seed is constant, then getting the same output from the generator is expected. The result from `random_device` itself being constant is...sub-optimal, to put it mildly (but a quick test confirms it with MinGW). – Jerry Coffin Jan 08 '16 at 17:11
  • 1
    Yeap. It's a bug. It is fixed in version 5.3 –  Jan 08 '16 at 17:39
  • Should I write an answer to my own question? –  Jan 08 '16 at 17:42