Pergunta

Eu tenho um programa que usa o mt19937 gerador de números aleatórios a partir de boost :: aleatória. Eu preciso fazer um random_shuffle e quer que os números aleatórios gerados para este ser deste estado compartilhado de modo que possam ser determinista com relação ao Mersenne twister é gerado anteriormente números.

Eu tentei algo parecido com isto:

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);
}

Mas eu recebo um erro de template chamando random_shuffle com rand. No entanto, este obras:

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);
}

Provavelmente porque é uma chamada de função real. Mas, obviamente, isso não manter o estado do twister mersenne originais. O que da? Existe alguma maneira de fazer o que estou tentando fazer sem variáveis ??globais?

Foi útil?

Solução

Em C ++ 03, você não pode instanciar um modelo baseado em um tipo de função-local. Se você mover a classe rand fora da função, ele deve funcionar bem (disclaimer: não testado, poderia haver outros bugs sinistros).

Este requisito foi relaxado em C ++ 0x, mas eu não sei se a mudança foi implementada no modo C ++ 0x do GCC ainda, e eu seria muito surpreso de encontrá-lo presente em qualquer outro compilador.

Outras dicas

Nos comentários, Robert Gould pediu uma versão de trabalho para a posteridade:

#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);
}

Eu estou usando tr1 vez de boost :: aleatório aqui, mas não deve importar muito.

O seguinte é um pouco complicado, mas funciona.

#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);

Eu pensei que era importante ressaltar que este é agora bastante simples em C ++ 11 usando apenas a biblioteca padrão:

#include <random>
#include <algorithm>

std::random_device rd;
std::mt19937 randEng(rd());
std::shuffle(vec.begin(), vec.end(), randEng);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top