使用 Rand() 时模式的奇怪重复

Odd Repetitions of Patterns When Using Rand()

随机样本 password/string 生成器生成 32 个字符串。因此,生成随机数并保留 33 到 127 之间的随机数,因为这些是构成有效文本的 ASCII 值。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    srand(time(0));
    clock_t start = clock();

    long long iterations = 0;

    printf("Generating String...\n\n\t\" ");

    for (int i = 0; i < 32; i++)
    {
        long long holder = 0;
        while(holder < 33 || holder > 126)
        {
            holder = rand();
            iterations++;
        }
        putchar(holder);
    }

    clock_t end = clock();

    printf(" \"\n\n%.2lf s , %lld iterations & %lld avg\n",(double)(end - start)/CLOCKS_PER_SEC,iterations,iterations/32);

    return 0;
}

输出以一种或另一种形式重复字符串 DEX&H1_(okd/YVf8;49=el%<j:@"T,NU

一些输出:

Generating String...

    " DEX&H1_(okd/YVf8;49=el%<j:@"T,NU "

9.11 s , 893836506 iterations & 27932390 avg
Generating String...

    " xq?!#O]tDEX&H1_(okd/YVf8;49=el%< "

7.59 s , 768749018 iterations & 24023406 avg
Generating String...

    " MJxq?!#O]tDEX&H1_(okd/YVf8;49=el "

7.63 s , 748742990 iterations & 23398218 avg

在 Clang/macOS 上用 cc file.c -o file 编译。

您尝试获取范围内随机数的方法效率极低。它也很可能是您看到的重复的来源。

您应该将返回的数字减少到所需范围内。

for (int i = 0; i < 32; i++)
{
    int holder = (rand() % (126 - 33 + 1)) + 33;
    putchar(holder);
}

另一个答案中已经解决了如何正确执行的问题。这是关于“*odd repetitions”的部分,之后可能不是那么“odd”全部.

以下假设 typical rand() implementation 其中:

  • 所有可能的值都在 rand() return 前一个值之前恰好取一次;

  • 下一个 rand() 值仅取决于前一个值。

在这些假设下,34 = '\"'125 = '}' 之间的 94 个值将在一个循环中被 returned,然后将重复不变。然后发布的代码将始终 return 来自该循环的 32 个连续字符(包括环绕)

假设第一个 运行 return 是 32 个字符的字符串 DEX&H1_(okd/YVf8;49=el%<j:@"T,NU。这意味着 rand() 生成器的 94 字符循环包括该字符串,后跟剩余 62 个字符的一些排列。

然后下一个 运行 将产生一个 32 个字符的字符串,它与第一个字符串重叠至少 16 个字符,前提是第一个符合条件的字符的索引介于 [0, 15][78, 93]。发生这种情况的概率是 16 / 94 ≈ 17%。反之,没有这种重叠的概率是≈ 83%,在接下来的7运行秒内没有重叠的概率是0.83^7 ≈ 0.27。因此,在接下来的 7 运行 秒中第一个字符串获得“repetition”的机会是 ≈ 73% 即不足为奇。


[ EDIT ] 此外,它后面跟着一个直接的 pigeonhole 论点,即任何 6 运行 将产生至少两个具有子字符串的字符串长度为 16 或以上的共同点。