2

I would like to use built-in distribution, but add some constraints to it. I tried something like this, but i get same number when using function. How can i avoid this? Can i use distribution as a argument to the function?

double Cauchy(double Fm){
    std::default_random_engine generator;
    std::cauchy_distribution<double> distribution(Fm, 0.1);
    double number=distribution(generator);
    while(number<0)
        number=distribution(generator);
    if (number>1)
        number = 1;
    return number;
}

Now i changed function and it looks like this

double Cauchy_1(double Fm, std::random_device &rd){

    std::default_random_engine generator(rd());
    std::cauchy_distribution<double> distribution(Fm, 0.1);
    double number=distribution(generator);
    while(number<0)
        number=distribution(generator);
    if (number>1)
        number =1;
    return number;
}


std::random_device rd;
    int i=15;
    double Crm=0.1, num;
    while (i>0){
        num=Cauchy_1(0.1, rd);
        cout<<num<<endl;
        i--;
    }

It gives me different values, but values are the same on new run.

Dikzamen
  • 92
  • 1
  • 6

2 Answers2

4

You initialize std::default_random_engine generator; with the same default seed. You need to seed it to get different outputs if you instantiate it anew. There is std::random_device class you can use to get a new random seed.

Also, std::default_random_engine is slow class to instantiate/create so you are using it wrong.

ALX23z
  • 4,456
  • 1
  • 11
  • 18
  • 3
    You should seed the RNG once; if you try to just add seeding to this function it'll end up re-seeding each call, which isn't ideal. – Daniel H Dec 21 '19 at 12:01
3

Functions in the standard library like std::shuffle take a random number generator by a forwarding reference, not a distribution. You can do the same:

template<class URBG>
double cauchy_1(double fm, URBG&& gen) {
    std::cauchy_distribution<double> distribution(fm, 0.1);
    double number;
    do 
        number = distribution(gen);
    while (number < 0);
    return std::min(number, 1.0);
}

int main() {
    std::random_device rd;
    std::default_random_engine gen(rd());

    for (int i = 0; i < 10; ++i) {
        auto num = cauchy_1(0.1, gen);
        std::cout << num << std::endl;
    }
}

It still has same set of numbers if i rerun this code.

This is not the problem of this code, but the problem of std::random_device. As explained here, std::random_device may be implemented in terms of a pseudo-random number engine. Possible solutions can be found here.

For example:

std::default_random_engine gen(
    std::chrono::system_clock::now().time_since_epoch().count());
Evg
  • 25,259
  • 5
  • 41
  • 83
  • What "template" line do? – Dikzamen Dec 21 '19 at 13:47
  • @Dikzamen, it declares a [function template](https://en.cppreference.com/w/cpp/language/function_template). You can pass any random number generator to `cauchy_1`, that can be used with `std::cauchy_distribution`, without changing anything in `cauchy_1`. – Evg Dec 21 '19 at 13:57
  • It still has same set of numbers if i rerun this code. – Dikzamen Dec 21 '19 at 14:09
  • @Dikzamen, what is your platform and compiler? On some platforms `std::random_device` produces the same number on each run. See [this](https://stackoverflow.com/questions/18880654/why-do-i-get-the-same-sequence-for-every-run-with-stdrandom-device-with-mingw) and [this](https://stackoverflow.com/questions/45069219/how-to-succinctly-portably-and-thoroughly-seed-the-mt19937-prng) questions. – Evg Dec 21 '19 at 14:21