18

I am trying to create a one dimensional array and use a random number generator(Gaussian generator that generates a random number with means of 70 and a standard deviation of 10) to populate the array with at least 100 numbers between 0 and 100 inclusive.

How would i go about doing this in C++?

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
coder_For_Life22
  • 26,645
  • 20
  • 86
  • 118

4 Answers4

30

In C++11 this is relatively straight forward using the random header and std::normal_distribution (live example):

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>

int main()
{
    std::random_device rd;

    std::mt19937 e2(rd());

    std::normal_distribution<> dist(70, 10);

    std::map<int, int> hist;
    for (int n = 0; n < 100000; ++n) {
        ++hist[std::round(dist(e2))];
    }

    for (auto p : hist) {
        std::cout << std::fixed << std::setprecision(1) << std::setw(2)
                  << p.first << ' ' << std::string(p.second/200, '*') << '\n';
    }
}

If C++11 is not an option than boost also provides a library(live example):

#include <iostream>
#include <iomanip>
#include <string>
#include <map>
#include <random>
#include <boost/random.hpp>
#include <boost/random/normal_distribution.hpp>

int main()
{

  boost::mt19937 *rng = new boost::mt19937();
  rng->seed(time(NULL));

  boost::normal_distribution<> distribution(70, 10);
  boost::variate_generator< boost::mt19937, boost::normal_distribution<> > dist(*rng, distribution);

  std::map<int, int> hist;
  for (int n = 0; n < 100000; ++n) {
    ++hist[std::round(dist())];
  }

  for (auto p : hist) {
    std::cout << std::fixed << std::setprecision(1) << std::setw(2)
              << p.first << ' ' << std::string(p.second/200, '*') << '\n';
  }
}

and if for some reason neither of these options is possible then you can roll your own Box-Muller transform, the code provided in the link looks reasonable.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • Thanks for your answer. I'm reading your first suggested method, and I'm a bit confused about the last two parts, which ultimately means I don't see where we are generating the normally distributed numbers. What do we achieve with the part `std::map hist;` `for (int n = 0; n < 100000; ++n) {++hist[std::round(dist())];}` and then the part `for (auto p : hist) {...`? Thanks a bunch in advance. – user929304 Feb 07 '18 at 16:19
  • @user929304 `dist` generates the normal random variables ... `hist` is a set of buckets for displaying results to see a gaussian graph, looking at the live examples may help. – Shafik Yaghmour Feb 07 '18 at 18:22
  • Thanks a lot for getting back to me. I am playing around with the live example but still struggling. Briefly, I am trying to write a loop (that say runs 10 times), where at each run I generate a number that is chosen from a Gaussian distribution with *mean* 0 and *variance* 0.05. What I have done: `std::random_device rd;` `std::mt19937 e2(rd());` `std::normal_distribution dist(0, sqrt(0.05));` `for (int i=0; i<10; i++){std::cout << dist(e2) << '\n';}` and it seems to work but I don't know why I should pass `e2` to it? I understand `rd` is seed here, but why we need `e2`? – user929304 Feb 14 '18 at 15:06
11

Use the Box Muller distribution (from here):

double rand_normal(double mean, double stddev)
{//Box muller method
    static double n2 = 0.0;
    static int n2_cached = 0;
    if (!n2_cached)
    {
        double x, y, r;
        do
        {
            x = 2.0*rand()/RAND_MAX - 1;
            y = 2.0*rand()/RAND_MAX - 1;

            r = x*x + y*y;
        }
        while (r == 0.0 || r > 1.0);
        {
            double d = sqrt(-2.0*log(r)/r);
            double n1 = x*d;
            n2 = y*d;
            double result = n1*stddev + mean;
            n2_cached = 1;
            return result;
        }
    }
    else
    {
        n2_cached = 0;
        return n2*stddev + mean;
    }
}

you can read more at: wolframe math world

samad montazeri
  • 1,203
  • 16
  • 28
  • 1
    How can you make this have a random output each time you run? – Wolfy Apr 12 '17 at 02:29
  • 1
    @Wolfy It does! notice `rand()` function inside `rand_normal(double mean, double stddev)`. Maybe you are missing `srand(time(NULL))` before using this function, and hence you are always getting same numbers. – samad montazeri Apr 12 '17 at 03:43
4

In C++11 you would use the facilities provided by the <random> header; create a random engine (e.g. std::default_random_engine or std::mt19937, initialized with std::random_device if necessary) and a std::normal_distribution object initialized with your parameters; then you can use them together to generate your numbers. Here you can find a full example.

In previous versions of C++, instead, all you have is the "classic" C LCG (srand/rand), which just generates a plain integer distribution in the range [0, MAX_RAND]; with it you can still generate gaussian random numbers using the Box-Muller transform. (It might be useful to note that the C++11 GNU GCC libstdc++'s std::normal_distribution uses the Marsaglia polar method as shown herein.).

Herpes Free Engineer
  • 2,425
  • 2
  • 27
  • 34
Matteo Italia
  • 123,740
  • 17
  • 206
  • 299
2

With #include <random>

std::default_random_engine de(time(0)); //seed
std::normal_distribution<int> nd(70, 10); //mean followed by stdiv
int rarrary [101]; // [0, 100]
for(int i = 0; i < 101; ++i){
    rarray[i] = nd(de); //Generate numbers;
}
yizzlez
  • 8,757
  • 4
  • 29
  • 44