0

I'm trying to make a model of a zombie apocalipse in c++ using simple structs and a when I'm randomizing the population, I need some fields of the struct to have a value in the interval [0..1[. As I'm interested in a more statistically correct analysis, I choose to use the mt19937 engine to generate my "data". When playing around with this PRNG I couldn't find a way to generate a number in said range. Here's the code that I came up with:

int
main ( int argc, char** argv )
{

    mt19937_64 newr ( time ( NULL ) );
    std::cout << newr.max ( ) << endl;
    std::cout << newr.min ( );
    double rn;
    for(;;){
        rn = newr()/newr.max ();
        std::cout << rn << std::endl;
    }
}

But the only outputs that I get for the loop are zeros (0). A small print of the output is down:

18446744073709551615
0
0
0
0
0
0
0
0
0
0
0

Any ideas?

Pedro
  • 333
  • 1
  • 5
  • 24

2 Answers2

3

This happens because the return value of newr() and newr.max() are integers and the value returned by newr() is smaller than newr.mar(). The result of the division is a zero integer which is then converted to a double. To fix this use

rn = static_cast<double>(newr()) / newr.max();
Captain Obvlious
  • 19,754
  • 5
  • 44
  • 74
  • Thank You so much, as soon as i can, i'll mark this as the correct answer. I should have thought of this earlier lol. – Pedro Dec 30 '14 at 23:28
  • 1
    Would be better to do a `static_cast(foo)`, probably. – Alex Reynolds Dec 30 '14 at 23:29
  • @AlexReynolds Just to be idomatic, sure ;p – Captain Obvlious Dec 30 '14 at 23:30
  • I think newer versions of clang++ will choke on `(double)foo`-style casting. The `static_cast` approach may be more future-proof. YMMV. – Alex Reynolds Dec 30 '14 at 23:31
  • @AlexReynolds: why would they choke on valid C++ code? – Rufflewind Dec 30 '14 at 23:33
  • Also, whats the difference of using static_cast and just (double). Doesn't GCC (the compiler i'm using) compiles both the same way? – Pedro Dec 30 '14 at 23:34
  • Sorry, perhaps choke is too strong. That kind of casting can raise a “warning: use of old-style cast” compilation warning. Warnings are generally useful to fix. Pedro, the following SO question and answer succinctly explains C++-style casting, including `static_cast<>`: http://stackoverflow.com/a/5249436/19410 – Alex Reynolds Dec 30 '14 at 23:40
  • The following SO answer goes into more detail about old-style ("C") casts and why it is a good idea to get into the habit of avoiding them in C++ code: http://stackoverflow.com/a/332086/19410 – Alex Reynolds Dec 30 '14 at 23:44
  • 2
    @Pedro this will not give a uniform distribution, in particular `1.0` is extremely less likely to occur than any other bit combination. Any reason you're not using the standard library wrappers for this? – Mark Ransom Dec 30 '14 at 23:45
  • @MarkRansom AFIC the mt19937 should give a much more uniform distribution the standard 'rand()'. I think I've got some deficits on my C/C++ learning, what are the wrappers? – Pedro Dec 30 '14 at 23:48
  • @Pedro I'm talking about the classes in the `` header, they're meant to be used with `mt19937`. In particular [`std::uniform_real_distribution`](http://en.cppreference.com/w/cpp/numeric/random/uniform_real_distribution). The problem is not in the distribution of the engine but in the way they are mapped to the range. `uniform_real_distribution` sidesteps the problem by excluding the end of the range altogether. – Mark Ransom Dec 30 '14 at 23:53
  • @MarkRansom As I was reading the documentation for those classes, I got a little bit confused, and tried to keep it simple. This is just a personal project. My next step is to make GSL work in my windows machine, then I'll just use the normal distribution of the GSL. But thanks for explaining! – Pedro Dec 30 '14 at 23:59
3

You divide int by int and so have integer rounding.

A way to use the random engine is by one of the various distributions, in your case std::uniform_real_distribution:

std::mt19937_64 engine ( time ( NULL ) );
std::uniform_real_distribution<double> dist(0., 1.);
for(;;){
    const double rn = dist(engine);
    std::cout << rn << std::endl;
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302