Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using C++0x TR1 random in a class, for low overhead

I'm using VC 2010 and trying to keep the overhead and duplicated code of certain functions low, by placing the random definitions in the constructor of each class instance, then calling as necessary from there. What I have now, simplified, is:

#include <random>
#include <Windows.h>
mt19937 eng(GetTickCount());

class Cycles {
    int line;
    normal_distribution<> rand_norm;
    variate_generator<mt19937&,normal_distribution<>> r_norm;
public:
    Cycles() 
    : rand_norm(0.85,0.05),
      r_norm(eng,rand_norm) { 
        line=0; 
    }
}

Unfortunately that doesn't work, and I end up with this error:

\vc\include\random(513): error C2248: 'std::tr1::_Ewrap<_Engine,_Tgt_type>::operator =' : cannot access private member declared in class 'std::tr1::_Ewrap<_Engine,_Tgt_type>'

\vc\include\random(446) : see declaration of 'std::tr1::_Ewrap<_Engine,_Tgt_type>::operator ='

This diagnostic occurred in the compiler generated function 'std::tr1::variate_generator<_Engine,_Distrib> &std::tr1::variate_generator<_Engine,_Distrib>::operator =(const std::tr1::variate_generator<_Engine,_Distrib> &)'

I understand that these should be initialized prior to the opening of the constructor, or else it errors because of the lack of a default constructor, but I don't understand why this fails. My C++ fu is quite rusty.

Every example I've seen shows the distributor and generator being initialized globally or locally in the function that calls it, which seems silly to me, as I have several member functions that will be using r_norm that are called in a tight loop. It fails the smell test badly. Doesn't anyone know what I'm missing?

like image 926
SilverbackNet Avatar asked Feb 27 '23 01:02

SilverbackNet


2 Answers

bind() is used in c++0x instead of variate_generator<>:

#include <functional> // bind
#include <iostream>
#include <vector>
#include <random>

namespace {
  std::random_device generate_seed;
  std::mt19937 eng(generate_seed());    
  class Cycles {
    int line;
    std::normal_distribution<> rand_norm;
    std::function<double()> r_norm;
  public:
    Cycles(): line(0), rand_norm(0.85, 0.05), r_norm(std::bind(rand_norm, eng))
    {
      // print distribution
      std::vector<size_t> freq(200);
      for (int i = 0; i < 900; ++i) ++freq.at(std::round(r_norm()*100));

      size_t line = 0, max_line = freq.size()-1;
      for ( ; not freq[line] and line <= max_line;  ++line);
      for ( ; not freq[max_line] and max_line >= line; --max_line);
      for ( ; line <= max_line; ++line) {
        std::cout << line << '\t';
        for (size_t j = 0; j < freq[line]; ++j) std::cout << '*';
        std::cout << std::endl;
      }
    }
  };
}    
int main() {
  Cycles c;
}

The plot is inspired by C++0xFAQ.

Output

72 **
73 ***
74 ******
75 ********
76 *****************
77 ********************
78 *******************************
79 ************************************************
80 *************************************************
81 **********************************************************
82 ************************************************************
83 ***********************************************************
84 ************************************************************************
85 ********************************************************************************
86 *********************************************************************
87 ************************************************************
88 ****************************************************
89 *************************************
90 **********************************
91 **************************************
92 *************************
93 ******************
94 ********************
95 ************
96 ****
97 **********
98 ***
99 **
100 **
101 *
like image 175
jfs Avatar answered Mar 07 '23 11:03

jfs


don't have MSVC at hand, but with gcc, this will compile if you replace

variate_generator<mt19937&,normal_distribution<>> r_norm;

with

variate_generator<mt19937, normal_distribution<> > r_norm;

(note the lack of &)

Incidentally, std::random_device is probably a better source of randomness than GetTickCount(), although I don't know how it's implemented in MSVC.

like image 24
Cubbi Avatar answered Mar 07 '23 10:03

Cubbi