C语言中random函数怎么用?

99ANYc3cd6
预计阅读时长 16 分钟
位置: 首页 C语言 正文

random 函数并不是C语言标准库的一部分,它是 BSD Unix 系统(以及许多类Unix系统,如 macOS)中的一个扩展函数,在标准C(C89/C90, C99, C11等)中,对应的随机数函数是 rand()

c语言中的random函数
(图片来源网络,侵删)

random 函数的行为和用法会因操作系统而异,下面我将分别介绍 random 函数(在支持的系统上)和标准C的 rand() 函数,并对它们进行比较。


random 函数 (BSD/SysV 扩展)

random 函数通常被认为是比标准 rand() 更高质量的随机数生成器,因为它通常使用更好的算法(在BSD系统中是 arc4random,或者基于线性同余法的改进版本)。

函数原型

long random(void);
  • 功能:返回一个从 0RAND_MAX 之间的伪随机长整型数。
  • 头文件<stdlib.h>

关键特性

  • 更好的随机性random 通常比 rand() 产生更高质量的随机数序列,周期更长,分布更均匀。
  • 自动播种:这是 randomrand() 最大的区别之一。random 函数在程序首次调用时会自动使用一个随机的种子(通常是 /dev/urandom 或其他系统熵源),从而避免了 rand() 中常见的忘记调用 srand() 导致每次运行都产生相同序列的问题。
  • 无状态random 函数本身不维护状态,它依赖于一个“随机数发生器”的状态,你需要使用 srandom() 来播种,然后用 random() 来获取值。

相关函数

为了使用 random,你通常会用到一组配套的函数:

函数 原型 功能
srandom void srandom(unsigned int seed); 初始化随机数发生器(播种),如果你希望每次运行程序时都得到相同的随机序列(例如用于调试),可以手动调用它。
initstate char *initstate(unsigned int seed, char *state, size_t size); 更高级的用法,允许你为随机数发生器分配内存并指定状态缓冲区的大小。size 越大,随机性越好。
setstate char *setstate(char *state); 切换到之前由 initstate 保存的状态。

使用示例

在支持 random 的系统(如 Linux, macOS)上:

c语言中的random函数
(图片来源网络,侵删)
#include <stdio.h>
#include <stdlib.h> // 包含 random 和 srandom 的头文件
int main() {
    // 1. 播种 (可选)
    // 如果你希望每次运行都得到不同的序列,可以不调用 srandom(),它会自动播种。
    // 如果你希望得到可重复的序列,则手动调用。
    // srandom(time(NULL)); 
    // 2. 生成并打印5个随机数
    printf("5 random numbers using random():\n");
    for (int i = 0; i < 5; i++) {
        long r = random();
        printf("%ld\n", r);
    }
    return 0;
}

注意:在Linux上,random() 实际上可能是一个宏,指向 glibcrandom_r,但其接口和概念是相似的。


标准C的 rand() 函数

rand() 是C标准库中定义的随机数函数,在所有符合标准的C编译器上都可以使用。

函数原型

int rand(void);
  • 功能:返回一个从 0RAND_MAX 之间的伪随机整型数。
  • 头文件<stdlib.h>
  • RAND_MAX:是一个宏,定义在 <stdlib.h> 中,其值至少是 32767(即 2^15 - 1),但通常是更大的值,如 2147483647。

关键特性

  • 需要手动播种rand() 函数在程序启动后,其内部种子(一个初始值)是固定的(通常是1),如果你不调用 srand(),那么每次运行程序,rand() 生成的随机数序列都将是完全相同的,这是初学者最容易犯的错误。
  • 基于线性同余法rand() 通常使用一个简单的线性同余算法来生成随机数,这个算法速度快,但随机性质量不高,序列较短且可能存在相关性。

相关函数

函数 原型 功能
srand void srand(unsigned int seed); 初始化 rand() 使用的随机数种子。必须在第一次调用 rand() 之前调用
RAND_MAX int 类型的最大值,rand() 能返回的最大值。

使用示例

#include <stdio.h>
#include <stdlib.h> // 包含 rand 和 srand 的头文件
#include <time.h>   // 包含 time 函数的头文件
int main() {
    // 1. 播种 - 使用当前时间作为种子
    // time(NULL) 返回自1970年1月1日以来的秒数,确保每次运行种子都不同
    srand((unsigned int)time(NULL));
    // 2. 生成并打印5个随机数
    printf("5 random numbers using rand():\n");
    for (int i = 0; i < 5; i++) {
        int r = rand();
        printf("%d\n", r);
    }
    return 0;
}

random vs. rand() 核心区别

特性 random() (BSD) rand() (标准C)
标准性 非标准,是BSD/SysV扩展 标准C函数,所有平台都支持
返回类型 long int
播种 自动 (可选手动 srandom) 必须手动 (srand)
随机质量 通常更高,周期更长,分布更均匀 一般,算法简单,随机性较差
平台兼容性 Linux, macOS, BSD等 所有C编译器

如何生成特定范围的随机数?

无论是 random 还是 rand,它们生成的数都是 [0, RAND_MAX][0, LONG_MAX] 范围内的,实际应用中,我们通常需要某个特定范围的随机数,1100

错误的做法:rand() % N

// 错误!会导致分布不均
int r = rand() % 100; // 生成 0 到 99

问题RAND_MAX 不是 N 的整数倍,那么序列前面的几个数字出现的概率会比后面的数字高,如果 RAND_MAX 是 32767,32767 % 100 是 67,那么数字 0 到 67 出现的概率就比 68 到 99 高。

正确的做法:使用 rand() / RAND_MAX

// 正确!分布均匀
int r = (int)(rand() / (RAND_MAX + 1.0) * 100); // 生成 0 到 99
// 如果要生成 1 到 100
int r = (int)(rand() / (RAND_MAX + 1.0) * 100) + 1; 

原理rand() / (RAND_MAX + 1.0) 会生成一个 [0.0, 1.0) 区间内的小数,乘以 N 就得到了 [0.0, N) 区间内的数,再强制转换为整数,就得到了 [0, N-1] 的均匀分布。

对于 random() 的做法

原理完全相同,只是类型和宏名不同:

// 生成 1 到 100
long r = (long)(random() / ((double)LONG_MAX + 1.0) * 100) + 1;

在实际编程中,RAND_MAXLONG_MAX 的具体值可能未知,但上述方法保证了数学上的正确性。


总结与建议

  1. 可移植性优先:如果你的代码需要在所有C编译器上运行(特别是Windows上的MSVC),必须使用 rand()srand(),这是最安全、最标准的选择。

  2. 质量优先且平台可控:如果你的代码主要运行在Linux、macOS等类Unix系统上,并且对随机数质量有要求(如游戏、模拟、密码学等),优先使用 random(),它能提供更好的随机性,并且自动播种省去了麻烦。

  3. C++11及以后:如果你使用的是C++,强烈建议使用C++11引入的 <random> 库,它提供了多种高质量的随机数引擎(如 std::mt19937)和分布器(如 std::uniform_int_distribution),功能强大且易于使用,是现代C++中生成随机数的最佳实践。

  4. 加密安全绝对不要使用 rand()random() 来生成密码、密钥或任何与安全相关的随机数,这些函数是伪随机的,其结果是可预测的,对于加密安全的需求,应使用操作系统提供的专门接口,

    • Linux/Unix: /dev/random/dev/urandom
    • Windows: BCryptGenRandomCryptGenRandom
    • macOS: SecRandomCopyBytes
-- 展开阅读全文 --
头像
dede5.7小说模板如何获取或使用?
« 上一篇 今天
C语言 double格式化
下一篇 » 今天

相关文章

取消
微信二维码
支付宝二维码

目录[+]