【问题标题】:64 bits Seeds for random generators随机生成器的 64 位种子
【发布时间】:2013-11-01 19:53:45
【问题描述】:

我目前正在运行一个具有 8 个以上管道(线程)的多线程模拟应用程序。这些管道运行非常复杂的代码,该代码依赖于种子生成的随机序列。然后将序列归结为单个 0/1。

在将种子从主线程传递到处理管道后,我希望这种“随机处理”是 100% 确定性的。所以,我可以在第二次运行中复制结果。

所以,例如:(我有这个编码并且它工作)

Pipe 1 -> Seed: 123 -> Result: 0
Pipe 2 -> Seed: 123 -> Result: 0
Pipe 3 -> Seed: 589 -> Result: 1

当我需要运行 100M 或更多这些进程然后平均结果时,就会出现问题。可能100M中只有1个为1,其余为0。 很明显,我无法对 100M 随机值进行采样,并将 32 位种子提供给srand()

是否可以在 VS2010 中使用 64 位种子播种到 srand(),或者使用等效的方法?

rand() 在 2^32 之后是否重复自身(具有某种内部隐藏状态)?

谢谢

【问题讨论】:

  • rand 的周期为RAND_MAX,一般为 2^16-1,再多的种子也无法解决,最好使用更高质量的 PRNG。

标签: c++ c visual-studio-2010 64-bit srand


【解决方案1】:

您可以使用 C++11 的 random 工具来生成给定大小和种子大小的随机数,尽管该过程有点过于复杂,无法在此总结。

例如,您可以构造一个std::mersenne_twister<uint64_t, ...> 并用一个 64 位整数作为种子,然后获取指定分布内的随机数,这似乎就是您要寻找的。​​p>

【讨论】:

  • VS2010已经支持这个
  • 很有意思,我想我最后会用这个
【解决方案2】:

一个简单的 64 位 LCG 应该可以满足您的需求。 LCG 的位 n(从最低有效位开始计算为位 1)最多有周期(并且,如果参数选择正确,则正好)2^n,因此如果不需要它们,请避免使用低位,并且/或在输出上使用回火功能。在我对另一个问题的回答中可以找到示例实现:

https://stackoverflow.com/a/19083740/379897

并转发:

static uint32_t temper(uint32_t x)
{
    x ^= x>>11;
    x ^= x<<7 & 0x9D2C5680;
    x ^= x<<15 & 0xEFC60000;
    x ^= x>>18;
    return x;
}
uint32_t lcg64_temper(uint64_t *seed)
{
    *seed = 6364136223846793005ULL * *seed + 1;
    return temper(*seed >> 32);
}

【讨论】:

    【解决方案3】:

    您可以使用 XOR SHIFT 伪随机数生成器

    它速度快,效果很好——这是我的实现类的实际生成部分。我在伪随机数生成器的维基百科搜索中找到了有关此算法的信息...

    uint64_t XRS_64::generate(void)
    {
        seed ^= seed >> 12; // a
        seed ^= seed << 25; // b
        seed ^= seed >> 27; // c
        return seed  * UINT64_C(2685821657736338717);
    }
    

    它速度很快,而且你可以在构造函数中进行初始化

    XRS_64::XRS_64()
    {
        seed = 6394358446697381921;
    }
    

    seed 是一个 unsigned int 64 位变量,它在类中声明。

    class XRS_64
    {
    public:
        XRS_64();
        ~XRS_64();
        void init(uint64_t newseed);
        uint64_t generate();
    
    private :
        uint64_t seed; /* The state must be seeded with a nonzero value. */
    };
    

    【讨论】:

      【解决方案4】:

      我无法回答您的问题,但如果您发现自己不能做您想做的事,您可以实现自己的 pseudo-random algorithm generator,它将 uint64_t 作为种子。 如果您想要一些更严格的生成器(例如,用于加密目的),有更好的算法用于此目的,但 LCG 是我见过的最容易实现的算法。

      编辑

      实际上,您不能rand() 函数使用 64 位种子。你必须自己去。在this Wikipedia 表中,MMIX Donald Knuth 使用了一些参数来实现它。请注意,根据您使用的参数,您的随机数生成器周期的值将比 2^64 小得多,并且由于乘法,您可能需要一个大数字库来处理数学运算。

      【讨论】:

        【解决方案5】:

        我的建议是您直接控制该过程并设置您自己的高质量随机数生成器。这里的答案都没有经过适当的测试或验证 - 这是一个需要考虑的重要标准。

        即使在 16 位和 32 位机器上,只要并行运行其中的几个,就可以在很长一段时间内制作高质量的随机数生成器 - 受限于某些先决条件。这在此处进行了更深入的描述

        P.L'Ecuyer,“高效便携的组合随机数发生器”,CACM 31(6),1988 年 6 月,742-751。

        还提供了测试和验证结果。文章的可访问版本可以在网上找到。

        对于 32 位实现,建议采用 M₀ = 1 + 2×3×7×631×81031 (= 2³¹ - 85) 和 M₁ = 1 + 2×19×31×1019×1789 ( = 2³¹ - 249) 产生周期为 (M₀ - 1)(M₁ - 1)/2 ≡ 2×3×7×19×31×631×1019×1789×81031 ≡ 2⁶¹ - 360777242114 的随机数生成器。它们还发布了 16 位 CPU 的建议。

        种子被更新为 (S₀, S₁) ← ((A₀×S₀) mod M₀, (A₁×S₁) mod M₁),并且可以由此产生一个 32 位的值作为 S₀ - S₁ 的结果如果 S₀ ≤ S₁,则向上调整 M₀ - 1。如果 (S₀, S₁) 初始化为区间 [0,M₀)×[0,M₁) 中的整数值,则每次更新时它都保持在该区间内。您必须修改输出值以满足您的需要,因为它们的版本专门用于产生严格的积极结果;并且没有 0。

        前提条件是 (M₀ - 1)/2 和 (M₁ - 1)/2 互质且 A₀²

        对于 32 位,更新完成为 (S₀, S₁) ← (A₀×(S₀ - K₀×Q₀) - K₀×R₀, A₁×(S₁ - K₁×Q₁) - K₁×R₁) 与任何 S₀

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-08-23
          • 1970-01-01
          • 2016-03-14
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多