Guvi
Guvi

Reputation: 107

Adding Gaussian noise

I have a .arff file which contains a list of float numbers. I need to add to every number a gaussian noise, which in MATLAB would be:

m = m+k*randn(size(m)

where m is one of the numbers in the list and k is a standard deviation and has value 0.1. What is the C++ equivalent to randn()?

Could you please provide an example?

Upvotes: 9

Views: 31950

Answers (2)

Andrew
Andrew

Reputation: 5352

Use std::normal_distribution with an appropriate generator (std::default_random_engine will usually work). See http://en.cppreference.com/w/cpp/numeric/random for details on all of the random number generation facilities of the C++ standard library.

(live example)

#include <iostream>
#include <iterator>
#include <random>

int main() {
    // Example data
    std::vector<double> data = {1., 2., 3., 4., 5., 6.};

    // Define random generator with Gaussian distribution
    const double mean = 0.0;
    const double stddev = 0.1;
    std::default_random_engine generator;
    std::normal_distribution<double> dist(mean, stddev);

    // Add Gaussian noise
    for (auto& x : data) {
        x = x + dist(generator);
    }

    // Output the result, for demonstration purposes
    std::copy(begin(data), end(data), std::ostream_iterator<double>(std::cout, " "));
    std::cout << "\n";

    return 0;
}

Output:

0.987803 1.89132 3.06843 3.89248 5.00333 6.07448 

Further considerations

For decent statistical properties, you'll probably want to choose the std::mersenne_twister_engine generator (or, for convenience, the std::mt19937 predefined version), and seed it using std::random_device:

std::mt19937 generator(std::random_device{}()); 

[Note: Seeding from std::random_device is a good practice to get into; if you use the current time as a seed, you can end up with the same seed value across multiple generators (e.g. when initialising several generators in a very short period of time). std::random_device will obtain entropy from the system, if available.]

In order to avoid passing the generator to the distribution every time, you can do something like:

auto dist = std::bind(std::normal_distribution<double>{mean, stddev},
                      std::mt19937(std::random_device{}()));

which you can then use as follows:

double val = dist();

(Live example with these modifications)

Upvotes: 13

Captain Giraffe
Captain Giraffe

Reputation: 14705

The c++ standard now includes several distributions for random numbers.

You are looking for std::normal_distribution.

In the documentation you can also find a code sample

  // construct a trivial random generator engine from a time-based seed:
  unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
  std::default_random_engine generator (seed);

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

  std::cout << "some Normal-distributed(0.0,1.0) results:" << std::endl;
  for (int i=0; i<10; ++i)
    std::cout << distribution(generator) << std::endl;

The parameters given to the constructor, std::normal_distribution, are first mean (0.0) and standard-deviation (1.0).

Upvotes: 4

Related Questions