-2

I have my function in Python for normal distribution. I need to convert it to C++ and i am not familiar with language.

Here is my Python:

def calculation(value):
    sigma = 0.5
    size = 10000
    x = 200

    x_distribution = np.random.normal(value, sigma, size)
    for i in x_distribution:
        x.append(i)
    return x

And it works as expected. I am trying to re-write same thing in C++ and found only the Link and where the "std::normal_distribution<> d{5,2}; " has to make magic. But i could not figure it out how to implement.

Here what i have tried and it is failing.

# include frame.distribution
Frame DistributionModel(x_mu, x_sigma)
{
    // Motion model;ignore it
    model = std::normal_distribution<> d{x_mu,x_sigma};

    return model;
}

Please, help me. Looking for any hints. Thanks.

Aconcagua
  • 24,880
  • 4
  • 34
  • 59
Cleo B.
  • 119
  • 3
  • 12
  • `std::normal_distribution<> d{x_mu,x_sigma};` make s a variable `d` but doesn't do anything with it. It looks like you might want to use `d` to generate `size` numbers. A `for` loop and a `std::vector` may be of use to you. No idea what a `Frame` or a `Model` is so I can't help much more than that. – user4581301 Apr 04 '18 at 00:17
  • But you are familiar with python, are you? You should keep an eye on correct formatting, especially in a language where indentation has significant meaning as in python... – Aconcagua Apr 04 '18 at 00:39
  • 2
    Suppose you should peek into a good [C++ book](https://stackoverflow.com/q/388242/1312382) first... – Aconcagua Apr 04 '18 at 00:42
  • Yes, i am familiar with Python. I copied and pasted from my enviroment and StackO just modified my function, even i tried to fix it – Cleo B. Apr 04 '18 at 01:11
  • I would recommend going through a [good book](https://stackoverflow.com/q/388242/9254539) and making sure that you got the basics down before worrying about generating random numbers. Unfortunately, C++ and Python have very different basic grammar. – eesiraed Apr 04 '18 at 04:17
  • see this awesome answer [Understanding “randomness”](https://stackoverflow.com/a/3956538/2521214) it will show you how easily to go from uniform distribution to gaussian. Then you will just need to tweak the scales to match your parameters ... – Spektre Apr 04 '18 at 07:18
  • another option is to use this [How to efficiently generate a set of unique random numbers with a predefined distribution?](https://stackoverflow.com/a/22422035/2521214) – Spektre Apr 04 '18 at 07:30
  • Thanks everyone for your suggestions and tips. – Cleo B. Apr 10 '18 at 17:15

2 Answers2

4

Well, trouble without end...

# include frame.distribution

Syntax for inclusion is:

#include <name_of_header_file>
// or:
#include "name_of_header_file"

(The space in between # and include does not harm, but is absolutely uncommon...)

Frame DistributionModel(x_mu, x_sigma)

C++ is a strongly typed language, i. e. you cannot just give variables a name as in Python, but you need to give them a type!

Frame DistributionModel(double x_mu, double x_sigma)

Same for local variables; type must match what you actually assign to (unless using auto)

std::normal_distribution<double> nd(x_mu, x_sigma);

This is a bit special about C++: You define a local variable, e. g.

 std::vector<int> v;

In case of a class, it gets already constructed using its default constructor. If you want to call a constructor with arguments, you just append the call to the variable name:

 std::vector<int> v(10); // vector with 10 elements.

What you saw in the sample is a feature called "uniform initialisation", using braces instead of parentheses. I personally strongly oppose against its usage, though, so you won't ever see it in code I have written (see me constructing the std::normal_distribution above...).

std::normal_distribution is defined in header random, so you need to include it (before your function definition):

#include <random>

About the return value: You only can return Frame, if the data type is defined somewhere. Now before trying to define a new class, we just can use an existing one: std::vector (it's a template class, though). A vector is quite similar to a python list, it is a container class storing a number of objects in contiguous memory; other than python lists, though, the type of all elements stored must be the same. We can use such a vector to collect the results:

std::vector<double> result;

Such a vector can grow dynamically, however, this can result in necessity to re-allocate the internal storage memory. Costly. If you know the number of elements in advance, you can tell the vector to allocate sufficient memory in advance, too:

result.reserve(max);

The vector is what we are going to return, so we need to adjust the function signature (I allowed to give it a different name and added another parameter):

std::vector<double> getDistribution(double x_mu, double x_sigma, size_t numberOfValues)

It would be possible to let the compiler deduce the return type, using auto keyword for. While auto brings quite a lot of benefits, I do not recommend it for given purpose: With explicit return type, users of the function see right from the signature what kind of result to expect and do not have to look into the function body to know about.

std::normal_distribution now is a number generator; it does not deliver the entire sequence at once as the python equivalent does, you need to draw the values one by another explicitly:

while(numberOfValues-- > 0)
{
    auto value = nd(gen);
    result.push_back(value);
}

nd(gen): std::normal_distribution provides a function call operator operator(), so objects of can be called just like functions (such objects are called "functors" in C++ terminology). The function call, however, requires a random number generator as argument, so we need to provide it as in the example you saw. Putting all together:

#include <random>
#include <vector>

std::vector<double> getDistribution
(
    double x_mu, double x_sigma, size_t numberOfValues
)
{
    // shortened compared to your example:
    std::mt19937 gen((std::random_device())());
    // create temporary (anonymous)     ^^
    // instance and call it immediately    ^^
    // afterwards

    std::normal_distribution<double> nd(x_mu, x_sigma);
    std::vector<double> result;
    result.reserve(numberOfValues);
    while(numberOfValues-- > 0)
    {
        // shorter than above: using result of previous
        // function (functor!) call directly as argument to next one
        result.push_back(nd(gen));
    }

    // finally something familiar from python:
    return result;
}
Aconcagua
  • 24,880
  • 4
  • 34
  • 59
0
#include<iostream>
#include<random>
#include<chrono>

int main() {
    unsigned seed = std::chrono::system_clock::now().time_since_epoch().count();
    std::default_random_engine generator(seed);
    std::normal_distribution<double> distribution(0.0, 3.0);
    double number = abs(distribution(generator));
    std::cout << number;
    std::cin.get();
    return 0;
}

This may help, create a random number using gaussian with mean=0.0 and std_dev= 3.0