关于rand()

本文介绍了如何使用C语言中的rand函数生成伪随机数,并通过两个示例函数展示如何生成指定数量和范围内的随机数。文章还解释了如何利用srand函数结合当前时间设置随机数种子以确保每次程序运行产生的随机数不同。

rand是CRT函数,功能是输出一个伪随机数,最大不超过RAND_MAX。下面是一个简单的示例:

/* a demo of rand
 * date: 2011-12-05
 * created: ume
 * remarks:
 *	注意输出格式
 */
#include<iostream>
#include<iomanip>
#include<time.h>
using namespace std;
// functions
void SimpleRand(int n)
{
	for(int i = 0; i < n; ++i)
	{
		cout<<setw(6)<<rand()<<endl;
	}
}
void RangedRand(int min, int max, int n)
{
	for(int i = 0; i < n; ++i)
	{
		cout<<setiosflags(ios_base::fixed)<<setw(6)<<setprecision(2)<<((double)rand()/(RAND_MAX + 1)*(max - min) + min)<<endl;
	}
}
// main function
void main()
{
	srand((unsigned int)time(NULL));
	SimpleRand(10);
	cout<<endl;
	RangedRand(-50, 50, 10);
	system("pause");
	return;
}

我们定义了两个函数SimpleRand()和RangedRand(),参数n表示产生随机数的数量,min和max表示随机数的大小范围。主函数在调用它们之前,调用了srand()来设置随机数发生器的初始状态。如果不设置或设置为某个固定的整数,程序每次运行的结果都一样。在示例中,我们使用了CRT函数time()获取本机的时间,它的返回值是距离1970年元旦凌晨流逝的秒数。程序每一次运行,获得的秒数都不一样,这就保证了每次输出都不相同。此外,在SimpleRand()和RangedRand()函数中我们对输出格式进行了控制,setw(6)表示输出长度是6位,setiosflags(ios_base::fixed)表示小数位长度固定,它与setprecision(2)共同起作用,使输出的小数的小数位总为2。运行示例程序,其结果如下所示:


<think>我们正在分析关于C语言rand()函数的四个选项。根据引用内容,我们可以逐一判断每个选项的正确性。 引用[1]说明:rand()是随机数生成器,srand()设置种子。如果不调用srand(),系统会自动调用一次。但相同的种子会产生相同的随机数序列。 引用[2]说明:即使设置srand,得到的还是伪随机数。如果使用固定种子,则序列固定;如果使用time(),则种子随时间变化,序列也会变化。 引用[3]说明:为了每次产生不同的随机数,需要用srand(time(NULL))设置种子,因为每次运行时间不同,种子就不同,随机数序列就不同。 选项A:rand()每次调用必返回不同的数值。 错误。因为rand()是伪随机数生成器,它依赖于种子。如果种子相同,则每次运行程序产生的序列都是相同的,而且在同一个程序中,连续调用rand()确实会返回不同的数(因为序列是连续的),但是注意,如果种子固定,那么每次运行程序,第一个rand()返回的值是固定的,第二个也是固定的,等等。但在同一个程序的一次运行中,连续调用rand()会得到序列中的不同值。然而,选项没有指明是“同一个程序的一次运行中连续调用”还是“不同次运行中调用”。但通常,我们关心的是不同次运行是否相同。而且,即使在同一运行中,如果序列足够长,也可能出现重复数值(但连续两次调用返回相同数值的可能性很小,因为序列是连续的)。但选项说“每次调用必返回不同的数值”过于绝对,因为: - 在同一个序列中,连续的两个随机数一般是不同的(除非序列重复,但通常不会),但是整个序列是有周期的,周期内数字可能会重复出现,但连续两次调用得到相同值的概率很小(除非设计不良的生成器)。然而,更重要的是,如果种子相同,那么每次程序运行时,第一次调用rand()返回的值总是相同的,第二次调用也是相同的,这样每次运行程序时,第一次调用得到的值是固定的,那么不同次运行中第一次调用得到的值相同(如果种子相同),但同一程序中连续两次调用得到的是序列中相邻的两个数,一般不同。 但是,选项A没有限定条件,它说“每次调用”都返回不同的数值,这是不正确的。因为: - 如果在不同的程序运行中,相同的种子会导致相同的随机数序列,所以第一次调用返回的值相同,那么不同次运行中调用rand()返回的值可以相同。 - 即使是同一个程序的一次运行中,如果随机数生成器的周期很长,但同一个数值在序列中可能出现多次(只是连续两次相同的情况很少),所以不能说“必返回不同的数值”。 所以,选项A错误。 选项B:rand()的返回值范围是0~RAND_MAX(含)。 正确。根据标准,rand()函数返回一个范围在0到RAND_MAX(包含)之间的整数。RAND_MAX是一个常量,通常至少是32767。所以选项B正确。 选项C:必须在每次调用前都执行srand(time(NULL))才能得到随机数。 错误。根据引用[1]和[3],我们只需要在程序开始调用一次srand()设置种子即可,不需要每次调用rand()前都设置。而且,引用[1]指出,如果没有调用srand(),系统会自动调用一次(相当于使用默认种子,通常是1)。所以,即使不调用srand()rand()也能产生随机数(只是序列固定)。另外,如果每次调用rand()前都调用srand(time(NULL)),由于time(NULL)返回的是秒级时间,如果在同一秒内多次调用,则种子相同,会导致rand()返回相同的值(因为种子重新设置为同一个值,序列重置)。所以,这样反而可能导致连续多次调用rand()返回相同的值。因此,选项C错误。 选项D:rand()%10能产生0~9的均匀分布。 不一定。虽然rand()返回的是均匀分布的整数(在0到RAND_MAX之间),但是当使用取模运算(%)时,如果RAND_MAX+1不是10的倍数,那么0~9的每个数字出现的概率就不完全相等。例如,假设RAND_MAX=32767,那么RAND_MAX+1=32768,除以10余8,因此,0到7出现的次数比8和9多一次(因为32768 ÷ 10 = 3276余8,所以0到7每个数出现3277次,而8和9出现3276次)。因此,产生的0~9的分布只是近似均匀,而不是严格的均匀分布。所以选项D错误。 综上所述,只有选项B正确。 因此,正确答案是B。 </think>根据引用内容,以下是对rand()函数选项的逐项分析,正确答案为**B**: ### 选项分析 1. **A. rand()每次调用必返回不同的数值** ❌ **错误** - rand()是伪随机数生成器,若种子相同则产生固定序列(如程序多次运行时若未重置种子,首次调用结果相同)[^1][^2] - 同一程序内连续调用返回不同值,但全局范围不具备真正随机性 - 数学表达:设种子$s$固定,则序列$\{R_n\}$满足$R_{k}=f(s,k)$,$k$为调用次数 2. **B. rand()的返回值范围是0~RAND_MAX(含)** ✅ **正确** - C标准规定rand()返回[0, RAND_MAX]区间的整数,RAND_MAX至少为32767 - 数学表达:$\forall n \in \mathbb{N}, 0 \leq \texttt{rand()} \leq \texttt{RAND\_MAX}$ - 引用佐证:标准库实现严格遵循此范围[^1][^3] 3. **C. 必须在每次调用前都执行srand(time(NULL))才能得到随机数** ❌ **错误** - srand()只需在**程序启动时调用一次**(通常在main()开头) - 每次调用前重复设置srand(time(NULL))会导致: - 同一秒内多次调用返回相同值(time()秒级精度) - 破坏序列连续性[^2][^3] - 未调用srand()时系统自动调用srand(1),仍产生伪随机数序列 4. **D. rand()%10能产生0~9的均匀分布** ❌ **错误** - 当RAND_MAX+1不是10的倍数时(如RAND_MAX=32767): - 设$M=\texttt{RAND\_MAX}+1$,$r=\texttt{rand()}$ - $P(r\%10=k) = \begin{cases} \frac{\lfloor M/10 \rfloor +1}{M} & k < M \mod 10 \\ \frac{\lfloor M/10 \rfloor}{M} & \text{其他} \end{cases}$ - 例如$k=0$的概率高于$k=9$(偏差约0.03%) - 仅当$10 \mid (\texttt{RAND\_MAX}+1)$时严格均匀 ### 正确使用方法 ```c #include <stdlib.h> #include <time.h> int main() { srand(time(NULL)); // 程序初始化时调用一次 int r1 = rand(); // 序列随机值1 int r2 = rand(); // 序列随机值2 // 避免rand()%n的不均匀问题,改用: // int r = rand() / (RAND_MAX / n + 1); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值