随机数生成C/C++

文章目录

  • 随机数生成C/C++
    • 1. 随机数概念
      • 1.1 真随机数
      • 1.2 伪随机数
    • 2. 随机函数
      • 2.1 rand函数
      • 2.2 srand函数
      • 2.3 time()函数
    • 3. 生成指定范围的随机数
      • 3.1 生成[0,100)的随机数
      • 3.2 生成[78,102)的随机数
      • 3.3 生成[m,n)的随机数
    • 4. 观察随机数分布
      • 4.1 0,1分布
      • 4.2 [m,n)分布概率
    • 5.随机数排序

1. 随机数概念

1.1 真随机数

  • 真随机数是从物理过程中获取的随机数,这些过程通常与自然现象相关,如放射性衰变、热噪声、光子计数等。
  • 真随机数的生成基于不可预测的物理现象,因此被认为是完全随机的。无法通过算法或计算来预测或重现它们。
  • 真随机数通常需要专用硬件设备来生成,例如硬件随机数生成器(HRNG)。

1.2 伪随机数

  • 伪随机数是通过算法生成的数列,起始于一个称为”种子”的初始值。这个算法通常是确定性的,因此伪随机数实际上不是真正的随机数。
  • 伪随机数生成器(PRNG)使用数学函数和初始种子来生成数列,这个数列在统计上表现出随机性,但是如果知道种子和算法,就可以重现相同的数列。
  • 伪随机数通常用于模拟、计算、游戏和密码学中,但在密码学中,通常需要更高质量的伪随机数生成器,以防止攻击者通过猜测种子或算法来破解密码。

2. 随机函数

2.1 rand函数

rand() 函数返回一个伪随机整数,通常在范围 [0, RAND_MAX] 内,其中 RAND_MAX 是一个常量,代表了伪随机数生成器的最大值。具体的 RAND_MAX 值取决于编译器和系统。

#include#includeusing namespace std ;int main(){int a = rand();for(int i = 0 ; i < 10 ; i++){int b = rand();cout << b << " " << endl;cout << a << " " << endl;}} 

运行结果:



根据b的值可以看出,代码中每调用一次随机函数,得到的结果不同,因为每次调用的种子(seed)不同。
种子是一个起始值或输入,它用来初始化随机数生成器。当使用相同的种子时,随机数生成器通常会生成相同的随机数序列,因此种子决定了随机数的可预测性。

多次运行后,发现每次运行结果都是一样的。这是因为 rand() 函数的随机性是基于初始的随机数种子和生成器算法。如果不设置随机数种子,或者每次设置的种子相同,那么生成器算法就会按照相同的方式生成相同的随机数序列。如果不主动设置种子,它通常会使用一个默认的种子,并且生成器算法是确定的,所以多次运行后的结果都是一样的。

关于种子是否随机:默认情况下,C标准库中的 rand() 函数通常使用一个固定的默认种子值,这个默认种子值在不同的编译器和平台上可能会有所不同。但需要注意的是,这个默认种子值通常是相对不随机的,因此在相同的程序运行中多次调用 rand() 函数将会生成相同的伪随机数序列。就比如,如果你用的也是Dev的话,你得到的a的值应该也是41。

2.2 srand函数

srand() 函数是C标准库中的一个函数,用于设置伪随机数生成器的种子值。它可以用于初始化随机数生成器,以便生成可重现的随机数序列或改变生成的随机数序列。

函数原型

void srand(unsigned int seed);

参数

seed:一个整数值,作为伪随机数生成器的种子。种子决定了生成的随机数序列。

返回值

srand() 函数没有返回值,它只用于设置随机数生成器的状态。

用法示例

#include#include#include using namespace std ;int main(){srand(time(NULL));int a=rand();for(int i=0;i<10;i++){int b=rand();cout<< b <<" " <<endl;cout<< a <<" " <<endl;}} 

运行结果:


上述示例中,srand(time(NULL)) 使用当前时间作为种子,以确保每次运行程序时都会生成不同的伪随机数序列。然后通过调用 rand() 函数生成伪随机整数。

2.3 time()函数

srand()函数中用到的 time() 函数是C标准库中的一个函数,用于获取当前的系统时间。它返回从某个固定日期(通常是1970年1月1日)以来经过的秒数,这个日期被称为Unix时间戳或Epoch时间。

函数原型

time_t time(time_t *timer);

参数

timer:一个指向 time_t 类型的指针,用于存储获取的时间值。可以传递 NULL,表示不需要存储时间值,只是获取当前时间。

返回值

time() 函数返回当前系统时间的时间戳,即从Epoch时间到现在所经过的秒数。

用法示例

#include #include using namespace std;int main() {time_t current_time=0;// 获取当前时间并存储到 current_time 变量中time(&current_time);// 打印当前时间cout << "Current Time: " << current_time << endl;return 0;}

运行结果:

上述示例中,首先定义了一个 time_t 类型的变量 current_time,然后通过调用 time(&current_time) 函数来获取当前的系统时间,并将其存储到 current_time 变量中。

3. 生成指定范围的随机数

3.1 生成[0,100)的随机数

#include#include#includeusing namespace std ;int main(){srand((unsigned)time(NULL));int a=rand();for(int i=0;i<100;i++){int b=rand()%100;cout<<b<<" ";}cout<<endl;} 

运行结果:

上述示例中,生成了100个[0,100)范围内的随机数。注意这里取不到100,最大取到的数是99。

采用的方法是用随机数去对100取余。

3.2 生成[78,102)的随机数

#include#include#includeusing namespace std ;int main(){srand((unsigned)time(NULL));int a=rand();for(int i=0;i<100;i++){int b=78+rand()%24;cout<<b<<" ";}} 

运行结果:

3.3 生成[m,n)的随机数

#include#include#includeusing namespace std ;int main(){int m,n;cin >> m >> n;srand((unsigned)time(NULL));int a=rand();for(int i=0;i<100;i++){int b=m+rand()%(n-m);cout<<b<<" ";}cout<<endl;return 0;} 

运行结果:

4. 观察随机数分布

4.1 0,1分布

#include#include#includeusing namespace std ;int main(){srand(time(NULL));int a=rand();int count1=0;int count2=0;for(int i=0;i<100;i++){int b=rand()%2;if(b==0)count2++; else if(b==1)count1++;cout<<b<<" ";}cout<<endl;cout<< "0:"<<float(count1)*100/(count1+count2)<< "%" << endl;cout<< "1:"<<float(count2)*100/(count1+count2)<< "%"<< endl;} 

循环100次

循环1000次

循环10000次

4.2 [m,n)分布概率

#include#include#includeusing namespace std ;int main(){int m,n;cin >> m >> n;srand((unsigned)time(NULL));int a=rand();int count[n-m+1]={0};for(int i=0;i<1000;i++){int b=m+rand()%(n-m);count[b-m]++;cout<<b<<" ";}cout<<endl;for(int j=0;j<(n-m);j++){cout<< j+m << ":"<< count[j] <<endl;}cout<<endl;return 0;} 

运行结果:

5.随机数排序

随机数快速排序用法示例:

#include#include#include using namespace std;void QuickSort(int *a , int begin ,int end ){int left = begin;int right = end;int key = left;if(left>=right){return ;}while(left=a[key]&&left<right){right--;}while(a[left]<=a[key]&&left> n; int a[n];srand(time(NULL));for(int i=0;i<n;i++){ a[i]=rand()%100;cout<< a[i] <<" " ;}cout<<endl;QuickSort(a,0, n-1);for(int i=0;i<n;i++){cout<< a[i] << " ";}} 

输入样例:

1000

输出样例: