有没有一个函数生成一个随机int数在C?或者我必须使用第三方库?
当前回答
我们来看看这个。首先,我们使用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;
}
其他回答
对于c, STL不存在,你必须调用rand,或者更好的是,随机。它们在标准库头文件stdlib.h中声明。rand是POSIX, random是BSD规范函数。
rand和random之间的区别是random返回一个更有用的32位随机数,而rand通常返回一个16位数。BSD手册显示rand的较低位是循环的和可预测的,因此rand对于较小的数字可能是无用的。
#include <stdio.h>
#include <dos.h>
int random(int range);
int main(void)
{
printf("%d", random(10));
return 0;
}
int random(int range)
{
struct time t;
int r;
gettime(&t);
r = t.ti_sec % range;
return r;
}
尽管这里所有人都建议使用rand(),但除非迫不得已,否则您不会想要使用rand() !rand()生成的随机数通常非常糟糕。引用Linux手册页:
Linux C库中的rand()和srand()版本使用与random(3)和srandom(3)相同的随机数生成器,因此低阶位应该与高阶位一样随机。但是,在旧的rand()实现上,以及在不同系统上的当前实现上,低阶位比高阶位随机得多。当需要良好的随机性时,不要在旨在可移植的应用程序中使用此函数。(请使用random(3)。)
关于可移植性,random()也由POSIX标准定义了很长一段时间。rand()更老,它已经出现在第一个POSIX.1规范(IEEE Std 1003.1-1988)中,而random()首次出现在POSIX.1-2001 (IEEE Std 1003.1-2001)中,然而当前的POSIX标准已经是POSIX.1-2008 (IEEE Std 1003.1-2008),仅在一年前收到了更新(IEEE Std 1003.1-2008, 2016版)。所以我认为random()是非常可移植的。
POSIX.1-2001还引入了lrand48()和mrand48()函数,参见这里:
此函数族应使用线性同余算法和48位整数算术生成伪随机数。
一个很好的伪随机源是arc4random()函数,它在许多系统上都可用。不是任何官方标准的一部分,在1997年左右出现在BSD中,但你可以在Linux和macOS/iOS等系统上找到它。
标准的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位打包到随机浮点数中。
你可以生成随机字符,然后将它们视为int:
#include <stdlib.h>
#include <stdio.h>
typedef double rand_type; // change double to int
rand_type my_rand() {
char buff[sizeof(rand_type)];
for (size_t i = 0 ; i < sizeof(rand_type) ; ++i)
buff[i] = (char) rand();
return *(rand_type *) buff;
}
int main() {
int i ; // srand as you want
for (i = 0 ; i < 10 ; ++i)
printf("%g\n", my_rand()); // change %g to %d
return 0 ;
}