使用 boost::random 洗牌向量时出现问题

Issue when shuffling a vector with boost::random

本文关键字:向量 问题 boost random 使用      更新时间:2023-10-16

我正在使用这段代码来生成一个向量的随机排列,使用费舍尔-耶茨随机化算法的变体(我从第一个元素到最后一个元素,而不是相反)。我正在一个程序中全局使用 boost::random::mt11213b RNG,该程序在程序启动时播种了generator.seed(time(NULL));,因此这里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填充后 25 个元素
  3. 洗牌数组。
  4. 从列表中取下前 5 个元素并将它们相加。

我重复这个过程几千次(循环,而不是手动:)),每次都从一个新的向量开始。然后我计算了总和的算术平均值,结果是0.98而不是预期的1.25

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

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

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

每次在向量被洗牌之前调用的行(也许它应该只调用一次程序,但这没有意义)

任何帮助将不胜感激!

如果我必须猜测原因,您不会每次循环都更改分布大小。计算机编程算法的艺术就在这里。

一旦你洗牌到n个元素,你就不想再碰前n个,因为重复应用伪随机数不会让事情变得更随机,而是使它们不那么随机。

不,你的算法是错误的。考虑向量为 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

而标准的费雪-耶茨算法将为所有结果提供一致的概率。

如果要洗牌向量,请直接使用 std::random_shuffle(有关一些示例代码,请参阅使用 boost::random 作为 std::random_shuffle 的 RNG)。