网站首页 > java教程 正文
ANSI-C库提供了rand()函数生成随机数。生成随机数有多种算法,ANSI-C允许C实现针对特定机器使用最佳算法。然而,ANSI-C标准还提供了一个可移植的标准算法,在不同系统中生成相同的随机数。
实际上,rand()是“伪随机数生成器”,意思是可预测生成数字的实际序列。但是,数字在其取值范围内均匀分布。为了看清楚程序内部的情况,我们使用可移植的ANSI版本,而不是编译器内置的rand()函数。可移植版本的方案开始于一个“种子”数字。该函数使用该种子生成新的数,这个新数又成为新的种子。然后,新种子可用于生成更新的种子,以此类推。该方案要行之有效,随机数函数必须记录它上一次被调用时所使用的种子。这里需要一个静态变量。程序rand0.c 演示了版本0(稍后给出版本1)。
/* rand0.c -- produces random numbers */
/* uses ANSI C portable algorithm */
static unsigned long int next = 1; /* the seed */
int rand0(void)
{
/* magic formula to generate pseudorandom number */
next = next * 1103515245 + 12345;
return (unsigned int) (next/65536) % 32768;
}
在上述程序中,静态变量next的初始值是1,其值在每次调用rand0()函数时都会被修改(通过魔术公式)。该函数是用于返回一个0~32767之间的值。注意,next是具有内部链接的静态变量(并非无链接)。这是为了方便稍后扩展本例,供同一个文件中的其他函数共享。
程序r_drive0.c是测试rand0()函数的一个简单的驱动程序。
/* r_drive0.c -- test the rand0() function */
/* compile with rand0.c */
#include <stdio.h>
extern int rand0(void);
int main(void)
{
int count;
for (count = 0; count < 5; count++)
printf("%dn", rand0());
return 0;
}
该程序也需要多文件编译。程序r_drive0.c和程序r_drive0.c分别使用一个文件。以上程序中的extern关键字提醒读者rand0()被定义在其他文件中,在这个文件中不要求写出该函数定义。输出如下:
16838
5758
10113
17515
31051
程序输出的数字看上去是随机的,再次运行程序后,输出如下:
16838
5758
10113
17515
31051
看来,这两次的输出完全相同,这体现了“伪随机”的一个方面。每次主程序运行,都开始于相同的种子1。可以引入另一个函数srand1()重置种子来解决这个问题。关键是要让next成为只供rand1()和srand1()访问的内部链接静态变量(srand1()相当于C库中的srand()函数)。把srand1()加入rand1()所在的文件中。程序s_and_r.c给出了修改后的文件。
/* s_and_r.c -- file for rand1() and srand1() */
/* uses ANSI C portable algorithm */
static unsigned long int next = 1; /* the seed */
int rand1(void)
{
/* magic formula to generate pseudorandom number */
next = next * 1103515245 + 12345;
return (unsigned int) (next/65536) % 32768;
}
void srand1(unsigned int seed)
{
next = seed;
}
注意,next是具有内部链接的文件作用域静态变量。这意味着rand1()和srand1()都可以使用它,但是其他文件中的函数无法访问它。使用程序with s_and_r.c的驱动程序测试这两个函数。
/* r_drive1.c -- test rand1() and srand1() */
/* compile with s_and_r.c */
#include <stdio.h>
extern void srand1(unsigned int x);
extern int rand1(void);
int main(void)
{
int count;
unsigned seed;
printf("Please enter your choice for seed.n");
while (scanf("%u", &seed) == 1)
{
srand1(seed); /* reset seed */
for (count = 0; count < 5; count++)
printf("%dn", rand1());
printf("Please enter next seed (q to quit):n");
}
printf("Donen");
return 0;
}
编译两个文件,运行该程序后,其输出如下:
Please enter your choice for seed.
1
16838
5758
10113
17515
31051
Please enter next seed (q to quit):
513
20067
23475
8955
20841
15324
Please enter next seed (q to quit):
q
Done
设置seed的值为1,输出的结果与前面程序相同。但是设置seed的值为513后就得到了新的结果。
可以把这个技巧应用于标准的ANSI-C函数srand()和rand()中。如果使用这些函数,要在文件中包含stdlib.c头文件。实际上,既然已经明白了srand1()和rand1()如何使用内部链接的静态变量,你也可以使用编译器提供的版本。我们将在下一个示例中这样做。
自动重置种子
如果C实现允许访问一些可变的量(如,时钟系统),可以用这些值(可能会被截断)初始化种子值。例如,ANSI C有一个time()函数返回系统时间。虽然时间单元因系统而异,但是重点是该返回值是一个可进行运算的类型,而且其值随着时间变化而变化。time()返回值的类型名是time_t,具体类型与系统有关。这没关系,我们可以使用强制类型转换:
#include <time.h> /* ANSI prototype for time() */
srand1((unsigned int) time(0)); /* initialize seed */
一般而言,time()接受的参数是一个time_t类型对象的地址,而时间值就存储在传入的地址上。当然,也可以传入空指针(0)作为参数,这种情况下,只能通过返回值机制来提供值。
- 上一篇: SpringBoot中静态变量注入方案,一网打尽
- 下一篇: C/C++中的内存四区
猜你喜欢
- 2025-01-08 VBA|变量的类型、声明、作用域
- 2025-01-08 西门子S7-1200变量如何使用?局部/全局变量、临时变量、静态变量
- 2025-01-08 长知识了!Java 关键字 transient 还能这么用
- 2025-01-08 「C++学习笔记(十)」理解类中的静态成员变量与静态成员函数
- 2025-01-08 Java程序员必备技能:静态方法的正确使用姿势!
- 2025-01-08 深入探索 Java 复杂泛型:使用与限制全解析
- 2025-01-08 Java类是如何加载的?
- 2025-01-08 CPU眼里的:静态、全局、临时变量
- 2025-01-08 面试官问我什么是JMM
- 2025-01-08 C/C++中的内存四区
你 发表评论:
欢迎- 04-24Java Collections 工具类集合框架中常用算法解析
- 04-24桶排序的简单理解
- 04-24Java集合框架底层实现原理大揭秘
- 04-24Java 集合框架全面解析:选对数据结构,提升开发效率
- 04-24c#集合排序
- 04-24Java面试中常被问到的集合类深度解读
- 04-24VBA技术资料MF278:对集合进行排序
- 04-24Spring 最常用的 7 大类注解,史上最强整理
- 最近发表
- 标签列表
-
- java反编译工具 (77)
- java反射 (57)
- java接口 (61)
- java随机数 (63)
- java7下载 (59)
- java数据结构 (61)
- java 三目运算符 (65)
- java对象转map (63)
- Java继承 (69)
- java字符串替换 (60)
- 快速排序java (59)
- java并发编程 (58)
- java api文档 (60)
- centos安装java (57)
- java调用webservice接口 (61)
- java深拷贝 (61)
- 工厂模式java (59)
- java代理模式 (59)
- java.lang (57)
- java连接mysql数据库 (67)
- java重载 (68)
- java 循环语句 (66)
- java反序列化 (58)
- java时间函数 (60)
- java是值传递还是引用传递 (62)
本文暂时没有评论,来添加一个吧(●'◡'●)