为什么linear_congruential_engine :: seed(Sseq)会丢弃种子序列生成的三个数字?

时间:2016-06-20 16:12:54

标签: c++

C ++标准(从C ++ 11一直到当前的C ++ 17草案)在[rand.eng.lcong]中说明如下:

template<class Sseq> explicit linear_congruential_engine(Sseq& q);
     

效果:构造一个linear_congruential_engine对象。使用 k =⌈log 2 m )÷32⌉和 a 数组32(或等效)长度 k + 3,调用q.generate(a + 0, a + k + 3)然后计算 S =(Σ j = 0 < sup> k -1 a j +3 ·2 32 j )mod m 。如果 c mod m 为0且 S 为0,则将引擎状态设置为1,否则将引擎状态设置为S.

为什么 a 0 a 1 a 2 丢弃?

1 个答案:

答案 0 :(得分:1)

这是我一直想弄清楚的事情。我有一个假设,但没有真正的证据。但是,规则起源于(N2079由@ T.C.链接的)的文件证实了我理论的一部分。

请注意,规则来自的函数接受文档中的std::seed_seq对象,而不是模板化类。这意味着在编写规则时,它是专门为std::seed_seq而制定的,而不是一般的SeedSequence的概念。这意味着我们可以查看std::seed_seq类以获取有关此信息的信息,特别是std::seed_seq::generate的定义方式。

std::seed_seq::generate使用的方法已得到很好的解释on cppreference.com。它有点复杂,但可以分为4个阶段。

  1. 使用一些初始数据初始化输出范围(我在这里包括k=0

  2. 将原始种子数据移至输出范围(k=1..s

  3. 将种子数据扩展到输出范围的其余部分(k=s+1..m-1,其中m=max(s+1, n)

  4. 随机输出范围内的数据(k=m..m+n-1

  5. 当使用modulo&lt; = 2 32 (包括std::linear_congruential_enginestd::minstd_rand)播种std::minstd_rand0时,它只需要生成1个值来自std::seed_seq,但是根据此规则,它会生成4.因此,当将n从1更改为4时,此算法会发生什么变化?

    改变的一个部分是改组阶段从1次迭代变为4.由于std::seed_seq的目标之一是产生高质量的播种值“给定小种子或分布不均的初始种子序列。 `,这些额外的混洗迭代可能会改善结果的种子值。它之所以丢弃前3个值而不是最后一个值的原因是因为后面的值(通常)是更多的混乱值。

    值得注意的是,所有4个阶段的关键等式是值begin[k]^begin[k+p]^begin[k−1](在最后阶段将XOR替换为加法)。在n=1时,这只会变为begin[k](或最后一个阶段的3*begin[k])(请注意,“输出范围begin[x]的索引采用模n”和{{ 1}})。当x % 1 == 0时,此等式更符合预期,这有助于更有效地改变数据。

    所以简短的回答是n=4丢弃由种子序列生成的3个数字,因为std::linear_congruential_engine生成这些数字可以提高实际使用的值的质量。现在,在定义SeedSequence的通用概念之前决定丢弃生成器中的这些数字,因此在生成器中解决问题更有意义,而不是使种子序列类过于复杂。但是,现在这意味着将丢弃由任何种子序列生成的前3个值。这是否值得,这可能是值得商榷的,但现在就是这样。