使用boost :: random改组矢量时的问题

时间:2012-04-23 19:10:33

标签: c++ boost random probability boost-random

我正在使用此代码使用Fisher-Yates随机化算法的变体生成向量的随机置换(我从第一个元素到最后一个元素,而不是相反)。我在程序启动时在boost::random::mt11213b播种的程序中全局使用generator.seed(time(NULL)); RNG,因此这里是一个包装单RandomNumber

boost::random::uniform_int_distribution<unsigned long> 
    distribution(0, vec.size()-1);

for (unsigned long i=0;i<vec.size();i++)
    std::swap(vec[i], vec[distribution(RandomNumber::getInstance().generator)]);

一些实验让我相信这个算法可能存在一个问题,简而言之。这就是我所做的

  1. 创建一个长度为100的整数向量
  2. 使用0填充前75个元素,使用1
  3. 填充最后25个元素
  4. 拖着一个阵列。
  5. 从列表中取出前5个元素并将它们相加。
  6. 我重复这个过程几千次(用一个循环,而不是手工操作:))每次都以一个新的向量开始。然后我计算了总和的算术平均值,它来自0.98而不是预期的1.25

    有趣的是,如果我从一个使用相同算法而不是有序算法一次洗牌的向量开始,结果会增加到1.22并且如果我不在每次迭代时丢弃该向量但只是将其再次洗牌,结果大约为1.25,即期望值。

    我不确定可能出现的问题。该算法看起来很合理,我能想到的唯一可能出错的是播种阶段和

    boost::random::uniform_int_distribution<unsigned long> 
        distribution(0, vec.size()-1);
    

    每次在向量被洗牌之前被调用的行(也许它应该只在一个程序中被调用但是不会有意义)

    任何帮助将不胜感激!

2 个答案:

答案 0 :(得分:3)

如果我不得不猜测原因,那么每次循环时你都不会改变分布大小。 计算机编程艺术算法是here

一旦你改组为n个元素,你不想再次触及前n个,因为伪随机数的重复应用不会使事情更随机,它们会使它们随机性降低。

答案 1 :(得分:2)

没有你的算法是错误的。考虑具有4个数字的向量的简单情况,您的算法返回以下偏差结果

result      probability * 256
{1,2,3,4}   10
{1,2,4,3}   10
{1,3,2,4}   10
{1,3,4,2}   14
{1,4,2,3}   11
{1,4,3,2}   9
{2,1,3,4}   10
{2,1,4,3}   15
{2,3,1,4}   14
{2,3,4,1}   14
{2,4,1,3}   11
{2,4,3,1}   11
{3,1,2,4}   11
{3,1,4,2}   11
{3,2,1,4}   9
{3,2,4,1}   11
{3,4,1,2}   11
{3,4,2,1}   10
{4,1,2,3}   8
{4,1,3,2}   9
{4,2,1,3}   9
{4,2,3,1}   8
{4,3,1,2}   10
{4,3,2,1}   10

虽然标准Fisher-Yates algorithm将为所有结果提供统一的概率。

如果您想要随机播放一个向量,请直接使用std::random_shuffle(有关示例代码,请参阅Using boost::random as the RNG for std::random_shuffle)。