分析 C++ rand()

mil*_*los 1 c++ random cryptography

我正在尝试预测由C++ rand()函数生成的数字。这是代码的链接,它可能使用:单击

这是我模拟rand() 的代码:

#include <iostream>
#include <cstdlib>
#include <ctime>

using namespace std;

int main() {
        srand(time(0));
        unsigned a = rand();
        unsigned b = rand();
        cout << (a * 1103515245U + 12345U) % 0x7fffffffU << '\n';
        cout << b << '\n'; // they should match, right? But they don't...
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

为什么我的值与b不匹配?

Win*_*ute 5

如果TYPE_0选择了生成器,glibc 仅使用旧的线性同余生成器,如您在链接的代码中所见。(默认情况下,它使用TYPE_3generator。)这是 RNG 缓冲区大小为 8 字节的唯一情况。您可以使用以下命令强制执行旧行为initstate

char state[8];
initstate(time(0), state, 8);

unsigned a = rand();
unsigned b = rand();
cout << (a * 1103515245u + 12345u) % 0x7fffffffu << '\n';
Run Code Online (Sandbox Code Playgroud)

然后你经常得到相同的数字,当你没有时,它只会被抵消一个。粗略一看,我还没有能够准确地弄清楚为什么会发生这种差异(稍后可能会编辑),但我怀疑进行一些恶作剧。

编辑:好的,我想通了。glibcrand内部使用有符号算术,它使用&而不是%模数。如果(a * 1103515245 + 12345)变为负数,这将产生一位差异。如果你写

int a = rand();
int b = rand();

cout << (a * 1103515245 + 12345) & 0x7fffffff << '\n';
Run Code Online (Sandbox Code Playgroud)

那么你总是得到相同的结果。嗯,真的a而且b应该是int32_t为了最大的便携性,但我怀疑这不是问题。因为无论如何,库的内部结构和可移植性是一种失败的原因。