快速避免模偏差的方法

时间:2011-11-29 23:40:10

标签: c++

我正在洗牌,它经常在一个小阵列上完成。可以是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;
}

1 个答案:

答案 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


使用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 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));