【问题标题】:C rand(). Issue with generating random stringsC 兰德()。生成随机字符串的问题
【发布时间】:2022-01-12 23:41:55
【问题描述】:

遇到生成随机字符串的问题。

下面的示例生成重复的随机字符串块。块中随机字符串的数量取决于“WORD_LENGTH”。对于 1M 'COUNT' 和 'WORD_LENGTH' 的 20 个字符,每个块包含 262144 (2^18) 个随机字符串,然后块重复。

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

#define WORD_LENGTH 20

//const char charset[62] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
const char charset[16] = "0123456789abcdef";

int main(int argc, char** argv) {
    srand(time(NULL));
    if (argc != 2) {
        printf("Usage: program COUNT'\n\n");
        return 0;
    }
    unsigned int count = atoi(argv[1]);
    char buf[WORD_LENGTH];
    for (int c = 0; c < count; c++ ) {
        for (int i = 0; i < WORD_LENGTH; ++i) {
            buf[i] = charset[ rand() % sizeof charset];
        }
        buf[WORD_LENGTH] = '\0';
        printf("%s\n", buf);
    }
    return 0;
}

重要的事情。当“..charset[62]...”与 'COUNT' 高达 100M 一起使用时,我无法重现“问题”。 问题:有人能解释一下为什么会这样吗?

【问题讨论】:

  • RAND_MAX&lt;stdlib.h&gt; 中定义的常量)是否设置为 32767 (2^15 - 1) 或 2147483647 (2^31 - 1) 或其他数字?
  • 你的内部循环“浪费”了一个随机值;循环将一个随机值写入buf[WORD_LENGTH - 1],然后循环之后的代码用空字节覆盖它。不是大问题,但有点粗心。
  • @Jonathan Leffler。是的。我明白了。

标签: c random random-seed


【解决方案1】:

C 在rand() 函数中使用Pseudorandom number generator。因此它们是重复序列。

【讨论】:

  • 问题以某种方式与“字符集”有关。我无法用“0123456789”重现。但是用“0123456789abcdef”或“abcdef0123456789abcdef0123456789”复制。对我来说很奇怪。
  • @Mark_85 尝试使用长度为 16 倍数的任何字符集。有兴趣看看您是否在其他地方发现类似的不受欢迎。当然,您可以通过使用加密安全的 rng 和均匀分布来消除模偏差来避开这个泥潭,但我怀疑您是否需要拿出核武器来杀死农作物雪貂。但是,如果您这样做是为了为设置新帐户之类的人生成随机密码,这可能不是一个坏主意。
  • 与序列周期有关。 AFAIK C 使用二的幂作为 mod。如果charset[16] 16 也是 2 的幂。但是如果charset[62]重复序列的长度为2^n * 31
【解决方案2】:

试试这个怎么样:

char buf[WORD_LENGTH];
for (int c = 0; c < count; c++ ) {
    for (int i = 0; i < WORD_LENGTH; ++i) {
        buf[i] = charset[ rand() / (RAND_MAX + 1u) * sizeof charset];
    }
    buf[WORD_LENGTH - 1] = '\0';
    printf("%s\n", buf);
}

C 参考中说,rand() % sizeof charset 之类的代码是有偏差的。这个答案可能会给出一些想法。

【讨论】:

  • 试过了。就我而言,它会生成零。
  • @Mark_85:当然可以。 RAND_MAX+1 总是大于rand() 返回的值,并且您使用的是整数除法,它会截断分数。所以你最终得到 0。你需要强制浮点:(int)(rand()/(RAND_MAX+1.0) * (sizeof charset))
  • @rici 测试 - 有效!
  • @Mark_85:酷。但重要的是你明白为什么它是必要的,因为这是一个非常常见的错误。 (例如,经常被问到的“为什么pow(x, 1/3) 不计算立方根?”)。
【解决方案3】:

总结来自@WhozCraig 和@LightVillet 的cmets。

发现的问题:

buf[i] = charset[ rand() % sizeof charset]

精确到 'rand() % X' 并与 'X' 连接,而不与 charset 数组连接。

问题重现时

X = 4,8,16,32,64. 

但不能以介于之间的值进行复制。用 COUNT 进行了简短的测试,最高可达 1M。

小心使用 rand() 并使用

(int)(rand()/(RAND_MAX+1.0) * (sizeof charset))

@Mr.Chip 和@rici 提到了这一点

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-18
    • 2017-08-01
    • 2011-06-30
    • 2014-03-26
    相关资源
    最近更新 更多