【问题标题】:Analysis of Linear congruential generator is wrong?线性同余生成器分析错了?
【发布时间】:2017-07-07 00:45:39
【问题描述】:

因此,为了更好地理解 MSVC++ 对 rand 的实现,我重新实现了它并试图更好地理解它(我猜一般是 LCG)。

我的实现(与 MSVC++ 几乎完全匹配)如下:

// vc++ impl. of random
// Xn+1 = (aXn + i) mod m
// a = 214013, i = 2531011, m = 32768
unsigned int seed = 0;
unsigned int random()
{
    seed = seed * 214013L + 2531011L;
    // return (seed/(1<<16)) % 32768; (equiv to below)
    return seed>>16 & 0x7FFF;
}

为了从 2 个种子中找出新生成的种子之间的差异,我认为它只是 (214013*h) % 2^32,其中 h 是 2 个初始种子之间的差异。使用相同的逻辑,我计算了两个随机生成的数字之间的差异,给定初始种子为x,下一个种子为x+h,我在种子中取了这个不同,将其除以 2^16(或将其右移 16 位),并去掉了最重要的位。

除了在某些情况下,例如当 x = 100 和 h = 5000 时,此产生的值似乎是正确的。

这是完整的代码:

#include <iostream>
#include <cstdlib>

// vc++ impl. of random
// Xn+1 = (aXn + i) mod m
// a = 214013, i = 2531011, m = 32768
unsigned int seed = 0;
unsigned int random()
{
    seed = seed * 214013L + 2531011L;
    return seed>>16 & 0x7FFF;
}

int main()
{
    // f(x) = (214013x + 2531011) mod 2^32 [LCG]
    // g(x) = floor(f(x)/2^16) mod 2^15 [RND]
    // h(x) = f(x + h) - f(x) ?= 214013*h mod 2^32
    // j(x) = g(x + h) - g(x) ?= 214013*h/2^16 mod 2^15

    // x: initial seed
    // h: displaecment to next seed (next seed: x + h)
    // a, b: first and second randomly generated values using C rand
    // c, d: first and second randomly generated values using random
    // newSeedA, newSeedB: seed generated from LCG after x and x + h respectively
    // diffExp: experimental difference in random values
    // diffCalc: calculated/theoretical difference in random vlaues
    unsigned int x = 100, h = 50000;
    unsigned int a, b, c, d;
    unsigned int newSeedA, newSeedB;
    int diffExp, diffCalc;

    srand(x);
    seed = x;
    a = rand();
    c = random();
    newSeedA = seed;

    srand(x + h);
    seed = x + h;
    b = rand();
    d = random();
    newSeedB = seed;

    diffExp = (d - c) % 32768;
    diffCalc = (214013*h)>>16 & 0x7FFF;


    std::cout << "RANDOM VALUES\n";
    std::cout << "  VC++ rand: " << a << ", " << b << "\n";
    std::cout << "Custom rand: " << c << ", " << d << "\n";
    std::cout << "\n";

    std::cout << "DIFFERENCE IN SEED\n";
    std::cout << "Experimental Difference: " << (newSeedB - newSeedA) << "\n";
    std::cout << "  Calculated Difference: " << (static_cast<unsigned int>(214013)*h) << "\n";
    std::cout << "\n";

    std::cout << "DIFFERENCE IN VALUES\n";
    std::cout << "Experimental Difference: " << diffExp << "\n";
    std::cout << "  Calculated Difference: " << diffCalc << "\n";
    std::cout << "\n";
    return 0;
}

但是,对于这些值,2 个随机生成的值之间的估计差值比实际差值小 1。我是不是做错了什么?

【问题讨论】:

  • 更糟糕的是,diffExp 可以为负数,但diffCalc 不能。
  • 同样正确,忘记说明这一点,但通过 32768 修改应该可以解决它。对此进行了更新。

标签: c++ random modular-arithmetic lcg


【解决方案1】:

新种子的区别确实是214013*h

这给出了种子ss + 214013*h,得到的随机输出之间的差异将是(在简化之前)diff = ((s + 214013*h &gt;&gt; 16) &amp; 0x7fff) - ((s &gt;&gt; 16) &amp; 0x7fff)。那么问题本质上是,这个表达式是否独立于s

事实并非如此。例如,即使取h = 1diff 也可以是 3(例如 s = 0)或 4(例如 s = 0x0000bc03)。

【讨论】:

  • diff 也将等于 214013/2^16(约 3.266)作为数字而不是整数,这将使其独立于 s,不是吗?
  • @Matthew 我将其称为 Q16 定点,我想您可以这么说。但这仍然不能让您计算实际差异,因为它的旋转方向取决于s
  • 有什么干净的方法可以解决这个问题吗?就像我可以为每 3.266 个值增加 1 的差异,如果这可行的话(尽管听起来我会遇到同样的问题)。
  • @Matthew 我不认为有,当然,当知道实际种子时,它只是微不足道的。顺便说一句,你用这个计算什么?
  • 只是为了好奇。
猜你喜欢
  • 1970-01-01
  • 2015-08-22
  • 2013-10-09
  • 1970-01-01
  • 2019-11-29
  • 2013-07-11
  • 2016-07-03
  • 2012-08-19
  • 1970-01-01
相关资源
最近更新 更多