Инициализация исходной последовательности в списке инициализации

В настоящее время я пытаюсь реализовать генератор случайных чисел (класс), который использует метод отклонения принятия. Поэтому мне нужны разные распределения случайных чисел С++ 11 (в моем случае нормальное распределение и равномерное распределение). Я хочу сделать случайные числа как можно лучше и, следовательно, хотел использовать следующее для создания функций:

 [...]
 #include <random>
 #include <vector>
 [...]
 std::vector<int> seeds(16);   
 std::mt19937 mt;
 std::minstd_rand seed_rng(101); // random seed  
 for(size_t i=0;i<16;++i) seeds[i]=seed_rng();
 std::seed_seq seq(seeds.begin(), seeds.end());
 mt.seed(seq);
 rng_normal = std::bind(ndist, std::ref(mt));
 [...]

Это работает отлично. Но когда я пытаюсь поместить все это сейчас в конструктор, я больше не могу использовать инициализацию последовательности семян. Я проверил ссылку на C++, но наткнулся только на std::seed_seq::generate, что не является правильным решением.
Есть ли способ построить seed_seq в моем списке инициализации после заполнения вектора? Ссылку на seed_seq см. здесь:
http://en.cppreference.com/w/cpp/numeric/random/seed_seq
Спасибо за любые предложения!


person LeoW.    schedule 20.01.2015    source источник
comment
В чем проблема разместить этот код в конструкторе? Или вы спрашиваете, можете ли вы сделать все в списке инициализации?   -  person Praetorian    schedule 20.01.2015
comment
@Praetorian Да, извините. Я хотел, чтобы все было сделано в списке инициализации.   -  person LeoW.    schedule 20.01.2015


Ответы (2)


Предполагая, что вы не заинтересованы в сохранении экземпляра seed_seq, используемого для создания mt19937, вы можете сделать что-то вроде этого:

 struct foo
 {
    std::mt19937 mt;
    std::normal_distribution<> ndist;
    std::function<decltype(mt)::result_type()> rng_normal;

    foo()
    : mt{make_mersenne_twister()}
    , rng_normal{std::bind(ndist, std::ref(mt))}
    {}

    static std::mt19937 make_mersenne_twister()
    {
        std::minstd_rand seed_rng(std::random_device{}()); // random seed
        std::vector<int> seeds(16);

        std::generate(seeds.begin(), seeds.end(), seed_rng);

        std::seed_seq seq(seeds.begin(), seeds.end());
        return std::mt19937{seq};
    }
 };

Я заменил ваше семя (101) на std::random_device.

Проблема с сохранением seed_seq заключается в том, что его нельзя ни копировать, ни перемещать, поэтому делегирование его построения функции, как я делаю с Mersenne Twister, невозможно.

Демо

person Praetorian    schedule 20.01.2015
comment
Голосуйте! Спасибо, это решение действительно должно работать для меня! Я думаю, что я буду искать, пока seed_seq на самом деле не перемещается и не копируется, так как я думаю, что у этого есть свои причины... - person LeoW.; 20.01.2015
comment
@ЛеоВ. Поскольку вы новичок и ваш комментарий указывает на то, что мой ответ помог, я укажу вам на часто задаваемые вопросы о том, как принятие полезного ответа работает. - person Praetorian; 27.01.2015

Я серьезно сомневаюсь, что ваше улучшение многого стоит. Конструктор с одним значением (и по умолчанию) для std::mt19937 указан в стандарте C++. Это составляет что-то вроде

static constexpr size_t WS = 32;
static constexpr result_type IM = 1812433253;
static constexpr result_type default_seed = 5489u;

explicit mt19937(result_type value = default_seed)
{
    state[0] = value;
    for (int i = 1; i != state_size; ++i)
    {
        state[i] = i + IM * (state[i - 1] ^ (state[i - 1] >> (WS - 2)));
    }
}

Таким образом, он использует генератор случайных чисел XOR-SHIFT для заполнения массива состояний. Учитывая людей, которые участвовали в разработке этого алгоритма заполнения, и людей, которые работали над внедрением <random> в Стандарт, я думаю, можно с уверенностью предположить, что они знали о std::minstd_ran, но сочли вышеприведенное превосходным для заполнения Мерсенн Твистер.

person user515430    schedule 24.01.2015