Использование boost::random в качестве ГСЧ для std::random_shuffle

StackOverflow https://stackoverflow.com/questions/147391

  •  02-07-2019
  •  | 
  •  

Вопрос

У меня есть программа, которая использует генератор случайных чисел mt19937 из boost::random.Мне нужно выполнить random_shuffle и хочу, чтобы случайные числа, сгенерированные для этого, были из этого общего состояния, чтобы они могли быть детерминированными по отношению к ранее сгенерированным числам мерсеннского твистера.

Я попробовал что-то вроде этого:

void foo(std::vector<unsigned> &vec, boost::mt19937 &state)
{
    struct bar {
        boost::mt19937 &_state;
        unsigned operator()(unsigned i) {
            boost::uniform_int<> rng(0, i - 1);
            return rng(_state);
        }
        bar(boost::mt19937 &state) : _state(state) {}
    } rand(state);

    std::random_shuffle(vec.begin(), vec.end(), rand);
}

Но я получаю ошибку шаблона при вызове random_shuffle с помощью rand.Однако это работает:

unsigned bar(unsigned i)
{
    boost::mt19937 no_state;
    boost::uniform_int<> rng(0, i - 1);
    return rng(no_state);
}
void foo(std::vector<unsigned> &vec, boost::mt19937 &state)
{
    std::random_shuffle(vec.begin(), vec.end(), bar);
}

Вероятно, потому, что это настоящий вызов функции.Но, очевидно, это не сохраняет состояние оригинального смерча Мерсенна.Что дает?Есть ли способ сделать то, что я пытаюсь сделать, без глобальных переменных?

Это было полезно?

Решение

В C++03 невозможно создать экземпляр шаблона на основе типа, локального для функции.Если вы переместите класс rand из функции, он должен работать нормально (отказ от ответственности:не проверялось, могут быть и другие зловещие ошибки).

Это требование было смягчено в C++0x, но я не знаю, реализовано ли это изменение в режиме GCC C++0x, и я был бы очень удивлен, обнаружив его в любом другом компиляторе.

Другие советы

В комментариях Роберт Гулд попросил рабочую версию для потомков:

#include <algorithm>
#include <functional>
#include <vector>
#include <boost/random.hpp>

struct bar : std::unary_function<unsigned, unsigned> {
    boost::mt19937 &_state;
    unsigned operator()(unsigned i) {
        boost::uniform_int<> rng(0, i - 1);
        return rng(_state);
    }
    bar(boost::mt19937 &state) : _state(state) {}
};

void foo(std::vector<unsigned> &vec, boost::mt19937 &state)
{
    bar rand(state);
    std::random_shuffle(vec.begin(), vec.end(), rand);
}

Здесь я использую tr1 вместо boost::random, но это не имеет большого значения.

Следующее немного сложно, но это работает.

#include <algorithm>
#include <tr1/random>


std::tr1::mt19937 engine;
std::tr1::uniform_int<> unigen;
std::tr1::variate_generator<std::tr1::mt19937, 
                            std::tr1::uniform_int<> >gen(engine, unigen);
std::random_shuffle(vec.begin(), vec.end(), gen);

Я подумал, что стоит отметить, что теперь в C++11 это довольно просто, используя только стандартную библиотеку:

#include <random>
#include <algorithm>

std::random_device rd;
std::mt19937 randEng(rd());
std::shuffle(vec.begin(), vec.end(), randEng);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top