2

Pardon me if this has been discussed already. I've got a template function which uses boost::uniform_int and boost::uniform_real depending on the template argument and should return the same type:

template <typename N> N getRandom(int min, int max)
{
  timeval t;
  gettimeofday(&t,NULL);
  boost::mt19937 seed((int)t.tv_sec);
  boost::uniform_int<> dist(min, max);
  boost::variate_generator<boost::mt19937&, boost::uniform_int<> > random(seed, dist);
  return random(); 
}
//! partial specialization for real numbers
template <typename N> N getRandom(N min, N max)
{
  timeval t;
  gettimeofday(&t,NULL);
  boost::mt19937 seed( (int)t.tv_sec );
  boost::uniform_real<> dist(min,max);
  boost::variate_generator<boost::mt19937&, boost::uniform_real<> > random(seed,dist);
  return random(); 
}

Now I've tested the function with int, float and doubles. It works fine with int, it works fine with double, but it does not work with floats. It's as if it either translates a float as an int, or there is some casting problem. Reason I'm saying this is because when i do:

float y = getRandom<float>(0.0,5.0);

I always get an int back. However, like I said, it works with doubles. Is there something I'm doing wrong or missing ? Thank you !

Mat
  • 202,337
  • 40
  • 393
  • 406
Ælex
  • 14,432
  • 20
  • 88
  • 129
  • 1
    Alex, you shouldn't generate random numbers in this way. You are regenerating your seed upon every call to the function, which means you lose all the nice guarantees a good PRNG can give you. The numbers you are generating may be, in fact, "non-random". – Richard May 04 '13 at 22:13
  • @Richard You are the first person to have observed this! I asked this question almost two years ago, and nobody noticed. And yes, you are absolutely right, I'm ruining the PRNG this way. I've since been using Mersenne Twister whenever I needed a proper PRNG. Thank you for mentioning it :) – Ælex May 05 '13 at 00:52

3 Answers3

7

The arguments 0.0,5.0 are doubles, not floats. Make them floats:

float y = getRandom<float>(0.0f,5.0f);
David Hammen
  • 32,454
  • 9
  • 60
  • 108
7

You can even avoid writing boilerplate code with type traits and MPL:

template <typename N>
N getRandom(N min, N max)
{
  typedef typename boost::mpl::if_<
    boost::is_floating_point<N>, // if we have a floating point type
    boost::uniform_real<>,       // use this, or
    boost::uniform_int<>         // else use this one
  >::type distro_type;

  timeval t;
  gettimeofday(&t,NULL);
  boost::mt19937 seed( (int)t.tv_sec );
  distro_type dist(min,max);
  boost::variate_generator<boost::mt19937&, distro_type > random(seed,dist);
  return random(); 
};
Juho
  • 976
  • 1
  • 13
  • 27
  • 1
    This code should not be used. It regenerates the seed on every call, which essentially defeats the purpose of the PRNG. – Richard May 04 '13 at 22:12
6

Not really addressing your question per se, but a solution:

Why not use a traits class to get the right distribution type?

template<class T>
struct distribution
{ // general case, assuming T is of integral type
  typedef boost::uniform_int<> type;
};

template<>
struct distribution<float>
{ // float case
  typedef boost::uniform_real<> type;
};

template<>
struct distribution<double>
{ // double case
  typedef boost::uniform_real<> type;
};

With that set, you can have one general function:

template <typename N> N getRandom(N min, N max)
{
  typedef typename distribution<N>::type distro_type;

  timeval t;
  gettimeofday(&t,NULL);
  boost::mt19937 seed( (int)t.tv_sec );
  distro_type dist(min,max);
  boost::variate_generator<boost::mt19937&, distro_type > random(seed,dist);
  return random(); 
};
Xeo
  • 129,499
  • 52
  • 291
  • 397
  • This code should not be used. It regenerates the seed on every call, which essentially defeats the purpose of the PRNG. – Richard May 04 '13 at 22:12
  • 2
    @Richard: Excuse me for solving OP's problem at hand - selecting the right distribution. Do you really think this is worth a downvote? Is this answer "not useful"? – Xeo May 04 '13 at 22:16
  • It is difficult to think of a compromised PRNG as being either useful or correct. If you were aware of the problem, you should have made the OP aware of it. If not, your code contributes to the propagation of a bad design. If you correct the problem in your code, I'll happily remove the downvote. – Richard May 04 '13 at 22:58