11

我有一个程序使用来自 boost::random 的 mt19937 随机数生成器。我需要做一个 random_shuffle 并希望为此生成的随机数来自这个共享状态,这样它们就可以确定 mersenne twister 先前生成的数字。

我试过这样的事情:

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

但是我收到一个模板错误,用 rand 调用 random_shuffle。但是,这有效:

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

可能是因为它是一个实际的函数调用。但很明显,这并不能保持原始梅森捻线机的状态。是什么赋予了?在没有全局变量的情况下,有什么方法可以做我想做的事情吗?

4

4 回答 4

13

在评论中,罗伯特古尔德要求为后代提供一个工作版本:

#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);
}
于 2008-09-29T03:42:31.137 回答
11

在 C++03 中,您不能实例化基于函数局部类型的模板。如果将 rand 类移出函数,它应该可以正常工作(免责声明:未经测试,可能存在其他险恶的错误)。

这个要求在 C++0x 中已经放宽了,但是我不知道这个改变是否已经在 GCC 的 C++0x 模式中实现了,如果发现它出现在任何其他编译器中,我会非常惊讶。

于 2008-09-29T03:29:36.160 回答
5

我在这里使用 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);
于 2010-03-16T19:55:09.380 回答
1

我认为值得指出的是,现在这在 C++11 中非常简单,只使用标准库:

#include <random>
#include <algorithm>

std::random_device rd;
std::mt19937 randEng(rd());
std::shuffle(vec.begin(), vec.end(), randEng);
于 2014-02-27T02:25:52.893 回答