前言
有时我们想用 rand() 生成一组随机数,虽然我们调用了 srand(),但生成的值还是一样。为什么会产生这种情况?又该如何解决?下面将用第一视角一起探究这其中的奥秘。
问题出现
场景描述:
我想生成一组整型随机数,放入数组中,用来测试自己的排序是否正确。于是我写出了下面的代码,用来生成随机数。
先简单了解下用到的函数:
// 成功时返回编码成 time_t 对象的当前日历时间
time_t time(time_t* timer);
// 以值 seed 播种 rand() 所用的随机数生成器
// 通常来说,应该只播种一次随机数生成器
// 在程序开始处,任何到 rand() 的调用前
void srand(unsigned seed);
// 产生一个伪随机数
// 返回 0 与 RAND_MAX 间的随机整数值
int rand(void);
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
int arr[10] = {0};
for (int i = 0; i < 10; i++) {
srand((unsigned)time(NULL));
// 两个相减是为了出现负的随机数,使测试范围更广
arr[i] = (rand() % 100 + 1) - (rand() % 100 + 1);
printf("%d ", arr[i]);
}
return 0;
}
我发现尽管我调用了 srand(),可生成的数组值还是同一个。
我思考后想到,因为 for 循环执行速度太快,整个程序都是在一秒内完成的。所以出现了都是同一个值的情况。
初步解决
于是我想出了下面的解决方法:
我可以在 for 循环内调用 sleep(),让我的电脑休眠一下,这样就不会出现上述情况了。
于是我写出了下方的代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
int main() {
int arr[10] = {0};
for (int i = 0; i < 10; ++i) {
sleep(1);
srand((unsigned)time(NULL));
arr[i] = (rand() % 100 + 1) - (rand() % 100 + 1);
printf("%d\n", arr[i]);
}
return 0;
}
通过休眠后,就成功解决问题了。
可是,如果睡眠时间太短,那么还是会出现重复的现象;如果睡眠时间太长,程序运行速度就太慢。
最终方法
因为上述的原因,我继续查询资料,了解了 rand() 和 srand() 的原理,成功解决了该问题。
给 srand() 传入一个数值后,srand() 会根据这个值生成一个随机序列表(通常有 4,294,967,296 个数),传入相同的数生成的序列表是相同的。然后 rand() 从序列的头部取出一个数返回,并将这个数放在随机序列表尾部。
此时,上面出现的问题也很好解决了。因为计算机运行速度很快,所以我们每次进入循环都会生成一个相同的随机序列表,rand() 只会取出其第一个数。
要解决这个问题,我们只需要在循环前调用一次 srand() 就好了,这样就不会重复生成序列表了。
下方是最终的代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
int arr[10] = {0};
srand((unsigned int)time(NULL));
for (int i = 0; i < 10; ++i) {
arr[i] = (rand() % 100 + 1) - (rand() % 100 + 1);
printf("%d ", arr[i]);
}
return 0;
}