Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Random Number Order in C++ using <random>

I have the following code, that I wrote to test a part of a larger program :

#include <fstream>
#include <random>
#include <iostream>
using namespace std ;

int main()
{
  mt19937_64 Generator(12187) ;
  mt19937_64 Generator2(12187) ;
  uniform_int_distribution<int> D1(1,6) ;

  cout << D1(Generator) << " " ;
  cout << D1(Generator) << " " << D1(Generator) << endl ;
  cout << D1(Generator2) << " " << D1(Generator2) << " " << D1(Generator2) << endl ;

  ofstream g1("g1.dat") ;
  g1 << Generator ;
  g1.close() ;
  ofstream g2("g2.dat") ;
  g2 << Generator2 ;
  g2.close() ;
}                                                            

The two generators are seeded with the same value, and therefore I expected the second row in the output to be identical to the first one. Instead, the output is

1 1 3
1 3 1

The state of the two generators as printed in the *.dat files is the same. I was wondering if there might be some hidden multi-threading in the random number generation causing the order mismatch.

I compiled with g++ version 5.3.0, on Linux, with the flag -std=c++11.

Thanks in advance for your help.

like image 741
Adriano Angelone Avatar asked Jan 28 '16 11:01

Adriano Angelone


People also ask

What does RAND () do in C?

rand() The function rand() is used to generate the pseudo random number. It returns an integer value and its range is from 0 to rand_max i.e 32767.

What is the range of rand () in C?

The C library function int rand(void) returns a pseudo-random number in the range of 0 to RAND_MAX. RAND_MAX is a constant whose default value may vary between implementations but it is granted to be at least 32767.


3 Answers

x << y is syntactic sugar for a function call to operator<<(x, y).

You will remember that the c++ standard places no restriction on the order of evaluation of the arguments of a function call.

So the compiler is free to emit code that computes x first or y first.

From the standard: §5 note 2:

Operators can be overloaded, that is, given meaning when applied to expressions of class type (Clause 9) or enumeration type (7.2). Uses of overloaded operators are transformed into function calls as described in 13.5. Overloaded operators obey the rules for syntax specified in Clause 5, but the requirements of operand type, value category, and evaluation order are replaced by the rules for function call.

like image 112
Richard Hodges Avatar answered Oct 17 '22 01:10

Richard Hodges


That's because the order of evaluation of this line

cout << D1(Generator2) << " " << D1(Generator2) << " " << D1(Generator2) << endl ;

is not what you think.

You can test it with this:

int f() {
  static int i = 0;
  return i++;
}

int main() {
  cout << f() << " " << f() << " " << f() << endl ;
  return 0;
}

Output: 2 1 0


The order is not specified by the C++ standard, so the order could be different on other compilers, please see Richard Hodges' answer.

like image 30
alain Avatar answered Oct 17 '22 02:10

alain


A slight change to the program reveals what happens:

#include <fstream>
#include <random>
#include <iostream>
using namespace std ;

int main()
{
  mt19937_64 Generator(12187) ;
  mt19937_64 Generator2(12187) ;
  uniform_int_distribution<int> D1(1,100) ;

  cout << D1(Generator) << " " ;
  cout << D1(Generator) << " " ;
  cout << D1(Generator) << endl ;
  cout << D1(Generator2) << " " << D1(Generator2) << " " << D1(Generator2) << endl ;
}

Output:

4 48 12
12 48 4

So your Generators produce equal results - but the order the arguments of your cout-line are calculated in different order.

Try it online: http://ideone.com/rsoqDe

like image 5
Anedar Avatar answered Oct 17 '22 02:10

Anedar