rand() 每次给出几乎相同的数字
rand() gives almost the same number every time
我正在学习 C,我想生成一个 0 到 6400 之间的数字。
这是我想出的代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand(time(0));
int i = (rand() % 6401);
printf("Random number between 0 and 6400: %d\n", i);
return 0;
}
当我从命令行编译和 运行 这段代码时,我得到了一些非常奇怪的结果:
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6282
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6282
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6285
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6285
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6289
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6289
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6292
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6292
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6295
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6298
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6298
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6302
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6302
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6305
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6305
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6308
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6308
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6311
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6311
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6315
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6315
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6318
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6318
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6321
K:\C\Labo\Oefeningen 2019>
数字各不相同,但我希望在 0 到 6400 之间稍微均匀分布。奇怪的是我在一个小时前使用相同的函数没有问题? (我以前用它来生成较小的数字。)我确信我错过了一些非常愚蠢的东西,但我现在已经被困了一个小时了。
编辑:我知道当您在同一秒内 运行 代码时,它会给出相同的值。我在两次执行之间等待了多秒 (10-20),但我仍然得到相同的结果?这些值很少相同,它们只是在 100% 的时间里非常非常非常相似。我该如何解决这个问题?
计算机并不真正生成随机数。因此,当您在同一秒内两次执行代码时,它 returns 具有相同的值。为了获得更好的结果,您可以在 srand.
中添加 getpid() 的值
请记住,这仍然不是真正的随机。
time()
分辨率为 1 秒。所以你的程序只会在平均半秒后生成不同的值。
如果您的编译器支持 C11,您可以使用更高分辨率的函数,timespec_get()
。然后,您的 srand(time(0));
将转换为以下内容:
struct timespec ts;
timespec_get(&ts, TIME_UTC);
srand(ts.tv_nsec);
这里 ts.tv_nsec
是时间戳的纳秒部分,其分辨率应该足以满足您的目的。
如果您的编译器不支持 C11,您仍然可以获得比 time()
更好的随机种子来源,分辨率约为毫秒(实际分辨率由 CLOCKS_PER_SEC
宏给出): clock()
函数。那么您的播种代码将是
srand(clock());
请注意,它实际上可能是一个糟糕的熵源,特别是如果您的 OS 不忙,那么程序将 运行 以某种可预测的速度进行。因为clock()
时代的开始与程序的执行有关,与实时无关。例如,可能会更好使用 clock()
和 time(0)
的总和来获得更多不可预测的值:
srand(time(0)+clock());
如果您的 rand
失败了,您可以尝试其中一种 xorshift 伪随机
数发生器。它们并不完美,但最终的实现非常简短。它可能足以供您自己使用。
这里是一个实现示例:我用这个one作为参考。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
uint64_t xorshift64s(uint64_t seed)
{
static uint64_t i = 1;
if (seed != 0)
i = seed;
i ^= i >> 12;
i ^= i << 25;
i ^= i >> 27;
i *= 0x2545f4914f6cdd1d;
return (i >> 32);
}
int main()
{
srand(time(0));
int i = (rand() % 6401);
printf("rand : Random number between 0 and 6400: %d\n", i);
xorshift64s(time(0));
int j = (xorshift64s(0) % 6401);
printf("xorshift: Random number between 0 and 6400: %d\n", j);
return 0;
}
如果其他人遇到这个问题,我想我找到了解决方法。我知道这不是一个完美的解决方案,但它是唯一对我有用的解决方案。我认为我的编译器中使用的随机数生成器根本不喜欢类似的种子。
使用此代码片段,它实际上生成了一些可接受的半随机数:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand((unsigned int)time(0) * 100000000);
int i = (rand() % 6401);
printf("Random number between 0 and 6400: %d\n", i);
return 0;
}
这是我从顺便说一句得到垃圾桶编译器的地方:http://tdm-gcc.tdragon.net/download
rand
生成的数字并不是真正随机的,它们是使用公式生成的。这就是为什么播种既是可能的也是必要的。根据使用的公式,种子和前几个随机数之间可能存在高度相关性。
解决方法是使用更好的公式(不是 rand
),使用更随机的种子,或者在播种后浪费一些随机数。
我正在学习 C,我想生成一个 0 到 6400 之间的数字。 这是我想出的代码:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand(time(0));
int i = (rand() % 6401);
printf("Random number between 0 and 6400: %d\n", i);
return 0;
}
当我从命令行编译和 运行 这段代码时,我得到了一些非常奇怪的结果:
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6282
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6282
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6285
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6285
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6289
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6289
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6292
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6292
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6295
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6298
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6298
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6302
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6302
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6305
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6305
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6308
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6308
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6311
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6311
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6315
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6315
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6318
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6318
K:\C\Labo\Oefeningen 2019>a
Random number between 0 and 6400: 6321
K:\C\Labo\Oefeningen 2019>
数字各不相同,但我希望在 0 到 6400 之间稍微均匀分布。奇怪的是我在一个小时前使用相同的函数没有问题? (我以前用它来生成较小的数字。)我确信我错过了一些非常愚蠢的东西,但我现在已经被困了一个小时了。
编辑:我知道当您在同一秒内 运行 代码时,它会给出相同的值。我在两次执行之间等待了多秒 (10-20),但我仍然得到相同的结果?这些值很少相同,它们只是在 100% 的时间里非常非常非常相似。我该如何解决这个问题?
计算机并不真正生成随机数。因此,当您在同一秒内两次执行代码时,它 returns 具有相同的值。为了获得更好的结果,您可以在 srand.
中添加 getpid() 的值请记住,这仍然不是真正的随机。
time()
分辨率为 1 秒。所以你的程序只会在平均半秒后生成不同的值。
如果您的编译器支持 C11,您可以使用更高分辨率的函数,timespec_get()
。然后,您的 srand(time(0));
将转换为以下内容:
struct timespec ts;
timespec_get(&ts, TIME_UTC);
srand(ts.tv_nsec);
这里 ts.tv_nsec
是时间戳的纳秒部分,其分辨率应该足以满足您的目的。
如果您的编译器不支持 C11,您仍然可以获得比 time()
更好的随机种子来源,分辨率约为毫秒(实际分辨率由 CLOCKS_PER_SEC
宏给出): clock()
函数。那么您的播种代码将是
srand(clock());
请注意,它实际上可能是一个糟糕的熵源,特别是如果您的 OS 不忙,那么程序将 运行 以某种可预测的速度进行。因为clock()
时代的开始与程序的执行有关,与实时无关。例如,可能会更好使用 clock()
和 time(0)
的总和来获得更多不可预测的值:
srand(time(0)+clock());
如果您的 rand
失败了,您可以尝试其中一种 xorshift 伪随机
数发生器。它们并不完美,但最终的实现非常简短。它可能足以供您自己使用。
这里是一个实现示例:我用这个one作为参考。
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <stdint.h>
uint64_t xorshift64s(uint64_t seed)
{
static uint64_t i = 1;
if (seed != 0)
i = seed;
i ^= i >> 12;
i ^= i << 25;
i ^= i >> 27;
i *= 0x2545f4914f6cdd1d;
return (i >> 32);
}
int main()
{
srand(time(0));
int i = (rand() % 6401);
printf("rand : Random number between 0 and 6400: %d\n", i);
xorshift64s(time(0));
int j = (xorshift64s(0) % 6401);
printf("xorshift: Random number between 0 and 6400: %d\n", j);
return 0;
}
如果其他人遇到这个问题,我想我找到了解决方法。我知道这不是一个完美的解决方案,但它是唯一对我有用的解决方案。我认为我的编译器中使用的随机数生成器根本不喜欢类似的种子。 使用此代码片段,它实际上生成了一些可接受的半随机数:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand((unsigned int)time(0) * 100000000);
int i = (rand() % 6401);
printf("Random number between 0 and 6400: %d\n", i);
return 0;
}
这是我从顺便说一句得到垃圾桶编译器的地方:http://tdm-gcc.tdragon.net/download
rand
生成的数字并不是真正随机的,它们是使用公式生成的。这就是为什么播种既是可能的也是必要的。根据使用的公式,种子和前几个随机数之间可能存在高度相关性。
解决方法是使用更好的公式(不是 rand
),使用更随机的种子,或者在播种后浪费一些随机数。