drand48函数在C语言中如何正确使用?

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

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

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 位的整数状态(通常称为“种子”或“状态”)。

  1. 种子状态: 内部有一个 48 位的整数 X
  2. 线性同余公式: 每次调用 drand48(),它都会用以下公式更新这个状态: X = (X * 25214903917 + 11) % 2^48 这个公式中的乘数和增量是经过精心选择的,以确保生成序列的周期长且随机性好。
  3. 生成浮点数: 更新后的 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() 相同,但使用传入的种子。

种子管理函数:

drand48函数 c语言
(图片来源网络,侵删)
  • 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语言
(图片来源网络,侵删)

重要注意事项

  1. 可移植性: 这是 drand48() 最大的缺点,它不是标准 C 库的一部分,因此在 Windows 平台上(特别是使用 MSVC 编译器时)无法直接使用,如果你需要编写跨平台的代码,应该优先考虑 C 标准库中的 rand()srand() 函数。

  2. 种子设置:

    • 永远不要在程序中多次调用 srand48(),尤其是在循环中,这会严重破坏随机数序列的统计特性,导致结果变得“可预测”且不随机。
    • 只在程序开始时调用一次 srand48() 来初始化种子,通常使用 srand48(time(NULL)) 来获得一个基于当前时间的、不同的种子。
  3. 线程安全: 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),是首选方案。
-- 展开阅读全文 --
头像
C语言和Java哪个对新手更友好?
« 上一篇 今天
dede登录为何总跳转登录页?
下一篇 » 今天

相关文章

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

目录[+]