C++Guns – RoboBlog

14.01.2016

std::normal_distribution

Filed under: Allgemein — Tags: — Thomas @ 16:01

Wie baut man aus gleichverteilen Zufallszahlen normalverteile?
Man nimmt std::normal_distribution

http://en.cppreference.com/w/cpp/numeric/random/normal_distribution

Und wie ist das Implementiert? Eine Beispielimplementation gibt es in der gnu stdc++

https://gcc.gnu.org/onlinedocs/gcc-4.7.4/libstdc++/api/a01267_source.html#l01678

Wtf? Versteht kein Mesch. Das Paper auf dass die sich beziehen ist auch ein Hammer.

http://www.eirene.de/Devroye.pdf Seite 249

Hier die Template bereinigte Version vom GNU


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

double round(double x) {
    return int(x*10)/10.0;
}

// erzeugt gleichverteilte zufallzahlen im interfall [0:1]
struct uniform_real_random_device {
    std::mt19937 gen;
    std::uniform_real_distribution<> uniform_dist = std::uniform_real_distribution<>(0.0, 1.0);

    double operator() () {
        return uniform_dist(gen);
    }
};

/**
  * Polar method due to Marsaglia.
  *
  * Devroye, L. Non-Uniform Random Variates Generation. Springer-Verlag,
  * New York, 1986, Ch. V, Sect. 4.4.
  *
  * https://gcc.gnu.org/onlinedocs/gcc-4.7.4/libstdc++/api/a01267_source.html#l01678
  */
double normal_dist(uniform_real_random_device& rand, double mean, double stddev) {
    double x, y, r2;
    do
    {
        x = 2.0 * rand() - 1.0;
        y = 2.0 * rand() - 1.0;
        r2 = x * x + y * y;
    }
    while (r2 > 1.0 || r2 == 0.0);

    double mult = std::sqrt(-2 * std::log(r2) / r2);
    double result = y * mult;
    result = result*stddev + mean;
    return result;
}

int main() {
    uniform_real_random_device uniformRand;

    std::map hist;
    for(int n=0; n<100000; ++n) {
        double gaussZahle = normal_dist(uniformRand, 0.5, 0.5);
        ++hist[round(gaussZahle)];
    }

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

-1.5
-1.4
-1.3
-1.2
-1.1
-1.0
-0.9 *
-0.8 *
-0.7 ***
-0.6 *****
-0.5 ********
-0.4 ************
-0.3 ******************
-0.2 **************************
-0.1 **********************************
0.0 ************************************************************************************************
0.1 **************************************************************
0.2 *********************************************************************
0.3 ****************************************************************************
0.4 *******************************************************************************
0.5 *******************************************************************************
0.6 ****************************************************************************
0.7 **********************************************************************
0.8 *************************************************************
0.9 *****************************************************
1.0 *******************************************
1.1 **********************************
1.2 **************************
1.3 ******************
1.4 *************
1.5 *********
1.6 *****
1.7 ***
1.8 **
1.9 *
2.0
2.1
2.2
2.3
2.4
2.5

Jaaa da ist noch ein Bug drin bei der 0. Wer ihn findet, darf mir eine Mail schreiben.

No Comments

No comments yet.

RSS feed for comments on this post.

Sorry, the comment form is closed at this time.

Powered by WordPress