drand48() 是 C 标准库中的一个函数,用于生成一个伪随机浮点数,它生成的数字在一个特定的范围内,并且具有良好的统计随机性。

(图片来源网络,侵删)
- 功能: 生成一个在
[0.0, 1.0)区间内均匀分布的伪随机浮点数。 - 返回值: 一个
double类型的值,大于或等于 0.0,且小于 1.0。 - 头文件:
<stdlib.h> - 注意:
drand48()是 POSIX 标准的一部分,在大多数 Unix-like 系统(如 Linux, macOS)上可用,但在标准的 C 语言库(如 MSVC 的 Windows 环境)中不可用,在可移植性要求高的场景下,通常推荐使用 C 标准库中的rand()函数。
函数签名
double drand48(void);
它不接受任何参数。
工作原理
drand48() 的随机数生成基于一个线性同余生成器,它内部维护一个 48 位的整数状态(通常称为“种子”或“状态”)。
- 种子状态: 内部有一个 48 位的整数
X。 - 线性同余公式: 每次调用
drand48(),它都会用以下公式更新这个状态:X = (X * 25214903917 + 11) % 2^48这个公式中的乘数和增量是经过精心选择的,以确保生成序列的周期长且随机性好。 - 生成浮点数: 更新后的 48 位状态
X会被转换成一个[0.0, 1.0)范围内的double值,转换方法是:将X视为一个无符号整数,然后除以2^48。
相关函数
drand48() 函数并不是孤立的,它属于一个“48系列”的随机数函数家族,这些函数共享同一个内部的 48 位种子,理解它们之间的关系很重要。
| 函数名 | 返回类型 | 范围 | 描述 |
|---|---|---|---|
drand48() |
double |
[0.0, 1.0) |
生成 double 类型的随机数。 |
erand48(unsigned short xsubi[3]) |
double |
[0.0, 1.0) |
功能与 drand48() 相同,但它允许传入自己的种子。 |
lrand48() |
long |
[0, 2^31) |
生成一个 31 位的非负长整型随机数。 |
nrand48(unsigned short xsubi[3]) |
long |
[0, 2^31) |
功能与 lrand48() 相同,但使用传入的种子。 |
mrand48() |
long |
[-2^31, 2^31-1] |
生成一个 32 位的(有符号)长整型随机数。 |
jrand48(unsigned short xsubi[3]) |
long |
[-2^31, 2^31-1] |
功能与 mrand48() 相同,但使用传入的种子。 |
种子管理函数:

(图片来源网络,侵删)
srand48(long seed): 初始化drand48()系列函数的种子,传入的seed会被用来初始化内部的 48 位状态。seed48(unsigned short seed[3]): 类似于srand48(),但它允许你设置一个完整的 48 位种子,它会返回一个指向内部状态的指针,这个指针可以被erand48,nrand48,jrand48使用。lcong48(unsigned short param[7]): 完全重置随机数生成器的参数(包括乘数、增量和初始状态),提供了更高级的控制。
使用示例
下面是一个完整的 C 程序示例,演示了如何使用 drand48() 和相关的种子设置函数。
#include <stdio.h>
#include <stdlib.h> // 包含 drand48() 和 srand48() 的头文件
#include <time.h> // 包含 time() 的头文件,用于获取当前时间作为种子
int main() {
// 示例 1: 使用 srand48() 设置种子
// 通常使用当前时间作为种子,以确保每次运行程序时生成的随机数序列都不同
srand48(time(NULL));
printf("--- 使用 srand48(time(NULL)) 设置种子 ---\n");
for (int i = 0; i < 5; i++) {
// 生成 5 个 [0.0, 1.0) 范围内的随机数
double random_value = drand48();
printf("drand48() #%d: %f\n", i + 1, random_value);
}
printf("\n");
// 示例 2: 使用固定的种子
// 如果使用固定的种子,每次运行程序时生成的随机数序列将是相同的
// 这对于需要可重复性的测试或模拟非常有用
srand48(12345L); // 使用固定的种子 12345
printf("--- 使用 srand48(12345L) 设置固定种子 ---\n");
for (int i = 0; i < 5; i++) {
double random_value = drand48();
printf("drand48() #%d: %f\n", i + 1, random_value);
}
printf("\n");
// 示例 3: 生成特定范围的随机数
// 生成 [10.0, 20.0) 范围内的随机数
// 公式: (drand48() * (max - min)) + min
double min = 10.0;
double max = 20.0;
printf("--- 生成 [10.0, 20.0) 范围内的随机数 ---\n");
for (int i = 0; i < 5; i++) {
double range_random = (drand48() * (max - min)) + min;
printf("Range Random #%d: %f\n", i + 1, range_random);
}
return 0;
}
编译和运行 (Linux/macOS):
gcc -o drand48_example drand48_example.c ./drand48_example
可能的输出:
--- 使用 srand48(time(NULL)) 设置种子 ---
drand48() #1: 0.812345
drand48() #2: 0.123456
drand48() #3: 0.987654
drand48() #4: 0.555555
drand48() #5: 0.111111
--- 使用 srand48(12345L) 设置固定种子 ---
drand48() #1: 0.636095
drand48() #2: 0.676183
drand48() #3: 0.110371
drand48() #4: 0.667649
drand48() #5: 0.945059
--- 生成 [10.0, 20.0) 范围内的随机数 ---
Range Random #1: 18.123450
Range Random #2: 11.234560
Range Random #3: 19.876540
Range Random #4: 15.555550
Range Random #5: 11.111110
(注意:由于时间是动态的,第一部分的输出每次都会不同,而第二部分因为种子固定,输出是确定的。)

(图片来源网络,侵删)
重要注意事项
-
可移植性: 这是
drand48()最大的缺点,它不是标准 C 库的一部分,因此在 Windows 平台上(特别是使用 MSVC 编译器时)无法直接使用,如果你需要编写跨平台的代码,应该优先考虑 C 标准库中的rand()和srand()函数。 -
种子设置:
- 永远不要在程序中多次调用
srand48(),尤其是在循环中,这会严重破坏随机数序列的统计特性,导致结果变得“可预测”且不随机。 - 只在程序开始时调用一次
srand48()来初始化种子,通常使用srand48(time(NULL))来获得一个基于当前时间的、不同的种子。
- 永远不要在程序中多次调用
-
线程安全:
drand48()系列函数通常不是线程安全的,因为它们共享一个全局的内部状态,如果在多线程环境中使用,你需要使用erand48(),nrand48(),jrand48()这些函数,并为每个线程维护自己的种子数组(unsigned short xsubi[3])。
drand48() vs. rand()
| 特性 | drand48() |
rand() |
|---|---|---|
| 标准 | POSIX 标准 | C 标准库 (ANSI C) |
| 可移植性 | 差 (主要在 Unix-like 系统) | 极好 (所有 C 编译器都支持) |
| 返回类型 | double |
int |
| 默认范围 | [0.0, 1.0) |
[0, RAND_MAX] (通常是 [0, 32767]) |
| 质量 | 通常更高,周期更长 | 质量一般,周期较短 |
| 线程安全 | 否 (需用 erand48 等) |
否 (需用 C11 的 rand_r 或其他方法) |
- 如果你的代码必须在 Windows、Linux、macOS 等多个平台上编译和运行,请使用
rand()。 - 如果你只在 Linux 或 macOS 等系统上工作,并且对随机数质量有较高要求,
drand48()是一个不错的选择。 - 在现代 C++ 中,
<random>库提供了更强大、更灵活、更高质量的随机数生成器(如std::mt19937),是首选方案。
