我正在洗牌,它经常在一个小阵列上完成。可以是1到10个元素。
我在这个问题上尝试了接受的答案:
Is this C implementation of Fisher-Yates shuffle correct?
不幸的是,它非常慢。
我需要一种更快的方法来做到这一点并避免我看到的模偏差。有什么建议吗?
修改 对不起,我应该指出,这不是缓慢的,这是用于生成随机int范围的方法。即rand_int()。我正在使用Mersenne twister算法,在我的情况下RAND_MAX是UINT_MAX帮助。当n远小于RAND_MAX
时,这当然会变慢我还发现了2个rand_int类型函数的实现。
static int rand_int(int n) {
int limit = RAND_MAX - RAND_MAX % n;
int rnd;
do {
rnd = rand();
} while (rnd >= limit);
return rnd % n;
}
以下内容要快得多。但是,它是否避免了模偏差问题?
int rand_int(int limit) {
int divisor = RAND_MAX/(limit);
int retval;
do {
retval = rand() / divisor;
} while (retval > limit);
return retval;
}
答案 0 :(得分:7)
修改强>
使用rand()
解决有关避免模偏差的基本问题,请参阅http://eternallyconfuzzled.com/arts/jsw_art_rand.aspx。
简而言之,除了跳过非域随机数 1 之外,你不能真正统一;本文列出了一些公式来获得较小的偏差(例如int r = rand() / ( RAND_MAX / N + 1 )
),而不会牺牲更多的性能。
1 请参阅Java的Random.nextInt(int)实现: http://download.oracle.com/javase/1.4.2/docs/api/java/util/Random.html#nextInt(int)
您应该可以使用std::random_shuffle
(来自<algorithm>
标题);
如果你必须推出自己的shuffle实现,我建议使用std :: random(TR1,C ++ 0x或Boost)。它带有许多发生器和发行版,具有不同的性能特征。
#include <random>
std::mt19937 rng(seed);
std::uniform_int_distribution<int> gen(0, N); // uniform, unbiased
int r = gen(rng);
有关Boost随机发生器和分布特性的详细概述,请参阅增强文档:
以下是直接使用Boost Random执行std::random_shuffle
的示例:
#include <algorithm>
#include <functional>
#include <vector>
#include <boost/random.hpp>
struct Rng
{
Rng(boost::mt19937 &rng) : _rng(rng) {}
unsigned operator()(unsigned i)
{
boost::uniform_int<> dist(0, i - 1);
return dist(_rng);
}
private:
boost::mt19937 &_rng;
};
boost::mt19937 state;
std::random_shuffle(v.begin(), v.end(), Rng(state));