1

I'm trying to build a function that returns a positive random number taken from a N(0,1) distribution.

I've looked around on the Internet and I tried to use two different methods.

This is the first one, in which I try to set the random seed from the system clock. I found it on this page of Cplusplus.com: std::normal_distribution::(constructor)

unsigned long normal01_rand() {

        unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();

        std::default_random_engine generator (seed); 

        std::normal_distribution<unsigned long> distribution (0.0, 1.0); 

        long random_value = distribution(generator);
        if (random_value < 0) {
            random_value = random_value * (-1);
        }
        return random_value;
}

And this is the second one. I didn't really understand how this works in detail but I found it as an answer to a similar question and I thought to give it a try:

unsigned long normal01_rand() {

        std::random_device rd;

        std::mt19937 e2(rd());

        std::normal_distribution<unsigned long> distribution (0.0, 1.0);

        long random_value = distribution(e2);
        if (random_value < 0) {
            random_value = random_value * (-1);
        }
        return random_value;
}

Unfortunately none of them works for me. If I use the first one my code gets stuck in an infinite loop when I first try to generate a random number in my code. The second one instead throws me this exception: EXC_ARITHMETIC (code=EXC_I386_DIV, subcode=0x0)

I can't understand what's going on and why.

Hoping to have been clear enough, thank you everybody in advance.

Community
  • 1
  • 1
jackscorrow
  • 682
  • 1
  • 9
  • 27
  • 1
    Need a [mcve] to know for sure but it looks like the biggest problem is you are recreating the PRNG every time you enter the function. You should only create and seed the generator once and then use that same generator for the life of the application. – NathanOliver Apr 06 '17 at 13:51
  • 2
    std:normal_distribution requires long double, double or float template argument. Otherwise you get undefined behavior. – user515430 Apr 06 '17 at 14:29
  • 1
    Your function name is a lie, what you seem to be attempting is a [half-normal](https://en.wikipedia.org/wiki/Half-normal_distribution), not a normal. – pjs Apr 06 '17 at 14:41
  • @NathanOliver The only way I can think of doing what you say is by instantiating the random generator in my `main` function and then pass it as argument to every class that might need it. Do you have a better idea? – jackscorrow Apr 06 '17 at 18:30
  • 1
    @jackscorrow Well you can make it static in the function so it is only initialized the first time the function is called. – NathanOliver Apr 06 '17 at 19:44
  • @NathanOliver Would you say something like: `static std::random_device rd;`, `static std::mt19937 e2(rd());`, `static std::normal_distribution distribution (0.0, 1.0);` ? Or make the entire function a static function? – jackscorrow Apr 07 '17 at 08:22
  • @NathanOliver I'm sorry I forgot to mention that I've put this function inside a namespace called "utils". Does this change anything? – jackscorrow Apr 07 '17 at 08:57
  • 1
    @jackscorrow Putting it in a namespace doesn't change anything. You don't need to make the distribution `static` but the other two should be. – NathanOliver Apr 07 '17 at 11:29
  • @NathanOliver So, just to be sure I understood correctly, if I put the `random_device` and the `mt19937` objects as `static` it means that they are going to be instantiated only once for the whole time my application will be running. Am I correct? – jackscorrow Apr 07 '17 at 12:35
  • 1
    @jackscorrow Yes. That means you do not reseed it every time the function is called. – NathanOliver Apr 07 '17 at 12:36

1 Answers1

2

It is defined as

template< class RealType = double > class normal_distribution

where for RealType you could use only float, double or long double, otherwise it is undefined.

Code should be

std::normal_distribution<double> distribution (0.0, 1.0);

double random_value = distribution(e2);
return fabs(random_value);
Severin Pappadeux
  • 18,636
  • 3
  • 38
  • 64