快速避免模偏置的方法
Fast way to avoid modulo bias
我正在进行洗牌,它经常在一个小数组上完成。可以是1 - 10个元素。
我已经尝试了这个问题的公认答案:
这个C实现的Fisher-Yates shuffle是正确的吗?
不幸的是,它非常慢。
我需要一种更快的方法来做到这一点,并避免我所看到的模偏差。有什么建议吗?
编辑:抱歉,我应该指出慢的不是shuffle,而是用来生成一个随机int范围的方法。即rand_int()。我使用的是梅森绕口令算法,在我的情况下,RAND_MAX是UINT_MAX来帮助。当n远小于RAND_MAX
时,这当然会使它变慢我还发现了两个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;
}
编辑
关于避免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)
使用c++
你应该能够使用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文档:
- http://www.boost.org/doc/libs/1_47_0/doc/html/boost_random/reference.html boost_random.reference.generators
下面是一个使用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));
- 为不同配置设置MSVC_RUNTIME_LIBRARY的正确方法是什么
- 通过方法访问结构
- 最小硬币更换问题(自上而下方法)
- C++为构建时间获取QDateTime的可靠方法
- 在C#中处理C++指针而不使用unsafe的最佳方法
- 处理多个异常集合的C++方法
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 有什么方法可以遍历结构吗
- 当类在C++中定义时,有什么方法可以"register"类吗?
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 实现无开销push_back的最佳方法是什么
- 使用std::函数映射对象方法
- 有符号的int和int-有没有一种方法可以在C++中区分它们
- C++从另一个类访问公共静态向量的正确方法是什么
- C++优先级队列,按对象的唯一指针的特定方法升序排列
- 没有为自己的结构调用列表推回方法
- 有没有什么方法可以使用一个函数中定义的常量变量,也可以由c++中同一程序中的其他函数使用
- 在类定义之后定义一个私有方法
- 枚举环境变量的惯用C++14/C++17方法
- 初始化具有非默认构造函数的std::数组项的更好方法