2

我正在尝试使用 Boost 的正态分布来生成给定不同种子的随机数。换句话说,我需要为 seed1、seed2 等生成相同的随机数;在模拟过程中,成千上万的种子将被传递给函数。随机数生成器永远不会被非种子使用。[编辑:“密钥”比“种子”更好——见下面的最终描述块。]我不确定生成单个 RNG 并重新设置它是否最有意义(如果是,如何)或如果每次生成一个新的更容易。这是我到目前为止所拥有的,其中涉及在每次请求随机正常数时构建一个新的种子 rng:


double rnorm( int thisSeed ) {
  boost::mt19937 rng( thisSeed );
  boost::normal_distribution<> nd( 0.0, 1.0 ); // (mean, sd)
  boost::variate_generator > var_nor( rng, nd );
  return var_nor();
}

这是哑巴吗?我是 PRNG 的新手,尤其是 Boost 的实施。


更全面地描述我为什么这样做:

我正在创建一个巨大的随机能量图来模拟蛋白质相互作用:每个序列都有一个特定的能量,该能量被计算为淬火高斯随机数的总和,该随机数取决于特定位置的特定氨基酸的值(以及一些其他序列属性)。我想使用 PRNG 来计算这些伪随机值是什么:这些值必须是一致的(相同的序列应该产生相同的值),但是要存储的太多了。举个简单的例子,我可能有一个序列 ARNDAMR 并根据两个子能量计算它的总能量:一个是随机正态数,取决于 A 在位置 1 和 D 在位置 4,另一个子能量是随机数取决于最后三个氨基酸。我' m 将配置转换为密钥,用作我的 PRNG 的种子(参数)。成千上万的序列将被构建和变异,所以我需要一种快速计算能量的方法——所以我需要知道如何最好地播种和调用我的 RNG。除了这些能量值“查找”之外,我不会将 Boost RNG 用于其他任何事情。


进一步(tl; dr)解释:

我将拥有介于 1 和 10^6 或 10^7 之间的整数的“关键”值。我希望每个都映射到一个高斯随机数。键值与其数字之间不应存在任何互相关(例如,键 145-148 不应映射到自相关的“随机”数字)。

每次在模拟中调用它(密钥)时,我都需要一个给定的密钥来返回相同的随机数。我不想将键随机数对存储在查找表中。

4

1 回答 1

2

您的方法从根本上误解了 PRNG 的工作原理。如果您在每次使用时都重新播种,那么您根本不会得到随机数,您只会得到种子的错误哈希函数。特别是,即使您调用 PRNG 的正态分布函数,您的数字也不会是正态分布的,因为 PRNG 只保证从特定种子生成的随机数是正态的。

如果您需要大量随机数来对一组特定的输入重复,然后生成一个作为这些输入函数的单个数字,用它为 PRNG 播种,然后以可预测的顺序从 PRNG 中获取数字;它将为相同的输入产生相同的序列,并且数字将由 PRNG 正确分配。

如果用于确定随机序列的输入集很大(特别是大于 PRNG 的种子大小),那么每组输入都不会有唯一的序列。这对您的应用程序来说可能没问题,或者您可能希望使用带有更大种子的 PRNG。

看看我的公共领域ojrandlib。它使用大种子,并使用快速 Ziggurat 算法生成正态分布的数字。


看到你的澄清后编辑:

啊,现在我明白了。没有“a”高斯随机这样的东西。分配仅对来自一个种子的整个序列有意义,因此您需要做的是创建一个生成器并为其播种,然后从该生成器中为每个键 N 获取第 N 个随机值。如果您不这样做这按顺序(也就是说,如果您完全随机地从键中获取而不是作为序列的一部分)这将非常慢,但仍然可能。您可能想查看是否可以强制执行序列,例如在获取键之前对键进行排序。

ojrandlib 也有这个功能discard(),因此如果您需要在序列中找到第 1,000,000 个数字,您可以播种 PRNG 并丢弃其中的 999,999 个,这比实际生成它们要快,但仍然会很慢。

可能更好:而不是使用您的密钥来播种高斯生成器,而是计算密钥 + 固定种子的良好哈希函数(这将导致均匀分布的随机位),然后将这些哈希位解释为两个统一的浮点数,然后执行 Box -Muller 或 Ziggurat 与那些改变分布的人。这样,您获得的数字将全部来自同一个“种子”(这是哈希的输入),但呈正态分布。你不需要加密安全的哈希,所以像 MurMurHash 这样的东西可能会很好用,尽管你最好为这样的特殊目的滚动你自己的。


认为我图书馆的用户可能会遇到与您类似的问题,所以我调查了一些可能性。以下是一些可能对您有用的代码:

/* Thomas Wang's 32-bit integer hash */
uint32_t nth_rand32(uint32_t a) {
    a -= a << 6;
    a ^= a >> 17;
    a -= a << 9;
    a ^= a << 4;
    a -= a << 3;
    a ^= a << 10;
    a ^= a >> 15;
    return a;
}

/* Marsaglia polar method */
double nth_normal(int index) {
    double f, g, w;
    int skip = 0;
    uint64_t x, y;

    do {
        x = (uint64_t)nth_rand32((index & ~1) + skip);
        y = (uint64_t)nth_rand32((index | 1) + skip);
        skip += 0x40000001;

        x = (x << 20) | 0x3ff0000000000000ull;
        f = *(double *)(&x) * 2.0 - 3.0;
        y = (y << 20) | 0x3ff0000000000000ull;
        g = *(double *)(&y) * 2.0 - 3.0;

        w = f * f + g * g;
    } while (w >= 1.0 || w == 0.0);

    w = sqrt((-2.0 * log(w)) / w);

    if (index & 1) w *= f;
    else w *= g;
    return w;
}

哈希没有通过顽固,但它非常好。我生成了 10,000,000 个随机法线,并得到了这个分布(如果这个图像上传有效):

分配

不完美,但也不算太差。使用更昂贵的哈希会好得多,但我会让你决定速度/准确性权衡在哪里适合你。

于 2013-06-28T00:40:22.170 回答