有没有一个函数生成一个随机int数在C?或者我必须使用第三方库?
当前回答
Rand()是生成随机数最方便的方法。
你也可以从任何在线服务如random.org捕获随机数。
其他回答
在我最近的应用程序中,我遇到了一个严重的伪随机数生成器问题:我多次通过Python脚本调用我的C程序,并使用以下代码作为种子:
srand(time(NULL))
然而,由于:
Rand将生成相同的伪随机序列,在srand中给出相同的种子(参见man srand); 如前所述,time函数每秒只会变化:如果应用程序在同一秒内运行多次,time每次都会返回相同的值。
我的程序生成了相同的数字序列。 你可以做三件事来解决这个问题:
mix time output with some other information changing on runs (in my application, the output name): srand(time(NULL) | getHashOfString(outputName)) I used djb2 as my hash function. Increase time resolution. On my platform, clock_gettime was available, so I use it: #include<time.h> struct timespec nanos; clock_gettime(CLOCK_MONOTONIC, &nanos) srand(nanos.tv_nsec); Use both methods together: #include<time.h> struct timespec nanos; clock_gettime(CLOCK_MONOTONIC, &nanos) srand(nanos.tv_nsec | getHashOfString(outputName));
选项3确保了你(据我所知)最好的种子随机性,但它可能只会在非常快速的应用中产生差异。 在我看来,选择2是一个安全的赌注。
标准的C函数是rand()。它可以用来发纸牌,但很糟糕。rand()的许多实现通过一个简短的数字列表循环,低位的周期更短。一些程序调用rand()的方式很糟糕,计算一个传递给srand()的好种子也很困难。
在C语言中生成随机数的最佳方法是使用第三方库,如OpenSSL。例如,
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <openssl/rand.h>
/* Random integer in [0, limit) */
unsigned int random_uint(unsigned int limit) {
union {
unsigned int i;
unsigned char c[sizeof(unsigned int)];
} u;
do {
if (!RAND_bytes(u.c, sizeof(u.c))) {
fprintf(stderr, "Can't get random bytes!\n");
exit(1);
}
} while (u.i < (-limit % limit)); /* u.i < (2**size % limit) */
return u.i % limit;
}
/* Random double in [0.0, 1.0) */
double random_double() {
union {
uint64_t i;
unsigned char c[sizeof(uint64_t)];
} u;
if (!RAND_bytes(u.c, sizeof(u.c))) {
fprintf(stderr, "Can't get random bytes!\n");
exit(1);
}
/* 53 bits / 2**53 */
return (u.i >> 11) * (1.0/9007199254740992.0);
}
int main() {
printf("Dice: %d\n", (int)(random_uint(6) + 1));
printf("Double: %f\n", random_double());
return 0;
}
为什么有这么多代码?其他语言,如Java和Ruby,都有用于随机整数或浮点数的函数。OpenSSL只提供随机字节,因此我尝试模拟Java或Ruby如何将它们转换为整数或浮点数。
对于整数,我们要避免模偏置。假设我们从rand() % 10000中得到一些随机的4位整数,但是rand()只能返回0到32767(就像在Microsoft Windows中那样)。0到2767之间的每个数字出现的频率要高于2768到9999之间的每个数字。为了消除偏差,我们可以在值低于2768时重试rand(),因为从2768到32767的30000值统一映射到从0到9999的10000值。
对于浮点数,我们需要53个随机位,因为double类型拥有53位精度(假设它是IEEE double类型)。如果我们使用超过53位,就会产生舍入偏差。有些程序员写rand() / (double)RAND_MAX这样的代码,但是rand()可能只返回31位,或者在Windows中只返回15位。
OpenSSL的RAND_bytes()可能通过读取Linux中的/dev/urandom来自行播种。如果我们需要很多随机数,从/dev/urandom读取它们会很慢,因为它们必须从内核复制。允许OpenSSL从种子中生成更多的随机数会更快。
更多关于随机数的内容:
Perl的Perl_seed()是一个如何在C中为srand()计算种子的例子。如果它不能读取/dev/ urrandom,它会混合来自当前时间、进程ID和一些指针的比特。 OpenBSD的arc4random_uniform()解释了模偏置。 random的Java API描述了从随机整数中去除偏差的算法,并将53位打包到随机浮点数中。
<stdlib.h>中的rand()函数返回一个介于0和RAND_MAX之间的伪随机整数。你可以使用srand(unsigned int seed)来设置种子。
通常的做法是将%操作符与rand()结合使用以获得不同的范围(但请记住,这在一定程度上破坏了一致性)。例如:
/* random int between 0 and 19 */
int r = rand() % 20;
如果你真的在乎一致性,你可以这样做:
/* Returns an integer in the range [0, n).
*
* Uses rand(), and so is affected-by/affects the same seed.
*/
int randint(int n) {
if ((n - 1) == RAND_MAX) {
return rand();
} else {
// Supporting larger values for n would requires an even more
// elaborate implementation that combines multiple calls to rand()
assert (n <= RAND_MAX)
// Chop off all of the values that would cause skew...
int end = RAND_MAX / n; // truncate skew
assert (end > 0);
end *= n;
// ... and ignore results from rand() that fall above that limit.
// (Worst case the loop condition should succeed 50% of the time,
// so we can expect to bail out of this loop pretty quickly.)
int r;
while ((r = rand()) >= end);
return r % n;
}
}
希望这比仅仅使用srand(time(NULL))更随机。
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
srand((unsigned int)**main + (unsigned int)&argc + (unsigned int)time(NULL));
srand(rand());
for (int i = 0; i < 10; i++)
printf("%d\n", rand());
}
我们来看看这个。首先,我们使用srand()函数来为随机化器播种。基本上,计算机可以根据输入给srand()的数字生成随机数。如果你给出相同的种子值,那么每次都会生成相同的随机数。
因此,我们必须用一个总是在变化的值来给随机化器播种。我们通过time()函数将当前时间的值提供给它来实现这一点。
现在,当我们调用rand()时,每次都会产生一个新的随机数。
#include <stdio.h>
int random_number(int min_num, int max_num);
int main(void)
{
printf("Min : 1 Max : 40 %d\n", random_number(1,40));
printf("Min : 100 Max : 1000 %d\n",random_number(100,1000));
return 0;
}
int random_number(int min_num, int max_num)
{
int result = 0, low_num = 0, hi_num = 0;
if (min_num < max_num)
{
low_num = min_num;
hi_num = max_num + 1; // include max_num in output
} else {
low_num = max_num + 1; // include max_num in output
hi_num = min_num;
}
srand(time(NULL));
result = (rand() % (hi_num - low_num)) + low_num;
return result;
}