资讯详情

c++STL随机数生成器

今天呢在OIwiki上面看到了一个奇怪的生成随机数函数:mt19937年,看到后直接看起来很傻。这是什么?

一开始,我以为这是一个名字M.T.19937937/1937年发明了函数,但回顾过去,他们发现了这一点mt好像是梅森缠绕器(好像有人说是梅森旋转算法),19937是质数,19937是2^19937-1,随后我只是在网上复制了一段代码,粘到DEV里面,然后我震惊地发现代码CE了

然后我抱着尝试的想法复制到最新版本VS2022年,然后我震惊地发现这个东西真的被编译了,生成了一个数字。看完之后,我决定测试这个随机性,所以我有以下代码

#include <cstdio> #include <ctime> #include <iostream> #include <random> using namespace std; int cnt[30050]; struct val {  int x;//下标  int y;//数量 }all; int main() {  srand(time(0));  std :: mt19937 rng(time(0));  //1-5000,5001-10000,10001-15000,15001-20000,20001-25000,25001-30000;  for (int i = 0; i < 1000000; i  ) {   unsigned int x = rng() % 30000   1;   //unsigned int x = rand() % 30000   1;   if (1 <= x && x <= 5000) cnt[1]  ;   else if (5001 <= x && x <= 10000) cnt[2]  ;   else if (10001 <= x && x <= 15000) cnt[3]  ;   else if (15001 <= x && x <= 20000) cnt[4]  ;   else if (20001 <= x && x <= 25000) cnt[5]  ;   else cnt[6]  ;  }  cout << "第一个数:1-5000 第二个数:5001-10000 第三个数:10001-15000 第四个数:15001-20000 第五个数:20001-25000 第六个数:25001-30000" << endl;  cout << cnt[1] << " " << cnt[2] << " " << cnt[3] << " " << cnt[4] << " " << cnt[5] << " " << cnt[6] << endl;  memset(cnt, 0, sizeof(cnt));  for (int i = 0; i < 1000000; i  ) {   unsigned int x = rng() % 30000   1;   //unsigned int x = rand() % 30000   1;   cnt[x]  ;  }  int maxn = -1, minn = 1000050;  for (int i = 1; i <= 30000; i  ) {   if (cnt[i] > maxn) maxn = cnt[i];   if (cnt[i] < minn) minn = cnt[i];  }  cout << "maxn:最多出现在1-30000中,minn:最少出现在1-30000中" << endl;  cout << "maxn - minn = " << maxn - minn << endl;  long long sum1 = 0, middle, sum2 = 0;  for (int i = 1; i <= 30000; i  ) {   sum1  = i * cnt[i];   if (sum2 < 500000 && sum2   cnt[i] >= 500000) middle = i   1;   sum2  = cnt[i];  }  double average = (double)sum1 / 1000000.0;  cout << "平均数:" << average << endl;  cout << "中位数:" << middle << endl;  maxn = -1;  for (int i = 1; i <= 30000; i  ) if (cnt[i] > maxn) maxn = cnt[i];  for (int i = 1; i <= 30000; i  ) if (cnt[i] == maxn) all.x = i, all.y = maxn;  cout << "众数:" << all.x;  return 0; }

经过n次测试,以下是差距最大的组:

可以看到,mt19937的随机性还是很好的,分布均匀,众数随机,平均,中位数接近,maxn-minn相对较小,测试后的随机性,我决定再次测试速度,添加几行代码

#include <cstdio> #include <ctime> #include <iostream> #include <random> using namespace std; int cnt[30050]; struct val {  int x;//下标  int y;//数量 }all; int main() {  srand(time(0));  std :: mt19937 rng(time(0));  //1-5000,5001-10000,10001-15000,15001-20000,20001-25000,25001-30000;  for (int i = 0; i < 1000000; i  ) {   unsigned int x = rng() % 30000   1;   //unsigned int x = rand() % 30000   1;   if (1 <= x && x <= 5000) cnt[1]  ;   else if (5001 <= x && x <= 10000) cnt[2]  ;   else if (10001 <= x && x <= 15000) cnt[3]  ;   else if (15001 <= x && x <= 20000) cnt[4]  ;   else if (20001 <= x && x <= 25000) cnt[5]  ;   else cnt[6]  ;  }  cout << "第一个数:1-5000 第二个数:5001-10000 第三个数:10001-15000 第四个数:15001-20000 第五个数:20001-25000 第六个数:25001-30000" << endl;  cout << cnt[1] << " " << cnt[2] << " " << cnt[3] << " " << cnt[4] << " " << cnt[5] << " " << cnt[6] << endl;  memset(cnt, 0, sizeof(cnt));  for (int i = 0; i < 1000000; i  ) {   unsigned int x = rng() % 30000   1;   //unsigned int x = rand() % 30000   1;   cnt[x]  ;  }  int maxn = -1, minn = 1000050;  for (int i = 1; i <= 30000; i  ) {   if (cnt[i] > maxn) maxn = cnt[i];   if (cnt[i] < minn) minn = cnt[i];  }  cout << "maxn:最多出现在1-30000中,minn:最少出现在1-30000中" << endl;  cout << "maxn - minn = " << maxn - minn << endl;  long long sum1 = 0, middle, sum2 = 0;  for (int i = 1; i <= 30000; i  ) {   sum1  = i * cnt[i];   if (sum2 < 500000 && sum2   cnt[i] >= 500000) middle = i   1;   sum2  = cnt[i];  }  double average = (double)sum1 / 1000000.0;  cout << "平均数:" << average << endl;  cout << "中位数:" << middle << endl;  maxn = -1;  for (int i = 1; i <= 30000; i  ) if (cnt[i] > maxn) maxn = cnt[i];  for (int i = 1; i <= 30000; i  ) if (cnt[i] == maxn) all.x = i, all.y = maxn;  cout << "众数:" << all.x;  clock_t start  clock();
	for (int i = 0; i < 10000000; i++) {
		unsigned int x = rng() % 30000 + 1;
		//unsigned int x = rand() % 30000 + 1;
	}
	cout << endl << "生成10000000个随机数的速度(ms):" << clock() - start;
	return 0;
}

 这个时候我发现这个mt19937几乎是个O(1)的算法,我准备再测一下rand函数的性能

首先是随机性

代码:

#include <cstdio>
#include <ctime>
#include <iostream>
#include <random>
using namespace std;
int cnt[30050];
struct val {
	int x;//下标
	int y;//数量
}all;
int main() {
	srand(time(0));
	std :: mt19937 rng(time(0));
	//1-5000,5001-10000,10001-15000,15001-20000,20001-25000,25001-30000;
	for (int i = 0; i < 1000000; i++) {
		unsigned int x = rng() % 30000 + 1;
		//unsigned int x = rand() % 30000 + 1;
		if (1 <= x && x <= 5000) cnt[1]++;
		else if (5001 <= x && x <= 10000) cnt[2]++;
		else if (10001 <= x && x <= 15000) cnt[3]++;
		else if (15001 <= x && x <= 20000) cnt[4]++;
		else if (20001 <= x && x <= 25000) cnt[5]++;
		else cnt[6]++;
	}
	cout << "第一个数:1-5000 第二个数:5001-10000 第三个数:10001-15000 第四个数:15001-20000 第五个数:20001-25000 第六个数:25001-30000" << endl;
	cout << cnt[1] << " " << cnt[2] << " " << cnt[3] << " " << cnt[4] << " " << cnt[5] << " " << cnt[6] << endl;
	memset(cnt, 0, sizeof(cnt));
	for (int i = 0; i < 1000000; i++) {
		unsigned int x = rng() % 30000 + 1;
		//unsigned int x = rand() % 30000 + 1;
		cnt[x]++;
	}
	int maxn = -1, minn = 1000050;
	for (int i = 1; i <= 30000; i++) {
		if (cnt[i] > maxn) maxn = cnt[i];
		if (cnt[i] < minn) minn = cnt[i];
	}
	cout << "maxn:在1-30000中出现最多的数,minn:在1-30000中出现最少的数" << endl;
	cout << "maxn - minn = " << maxn - minn << endl;
	long long sum1 = 0, middle, sum2 = 0;
	for (int i = 1; i <= 30000; i++) {
		sum1 += i * cnt[i];
		if (sum2 < 500000 && sum2 + cnt[i] >= 500000) middle = i + 1;
		sum2 += cnt[i];
	}
	double average = (double)sum1 / 1000000.0;
	cout << "平均数:" << average << endl;
	cout << "中位数:" << middle << endl;
	maxn = -1;
	for (int i = 1; i <= 30000; i++) if (cnt[i] > maxn) maxn = cnt[i];
	for (int i = 1; i <= 30000; i++) if (cnt[i] == maxn) all.x = i, all.y = maxn;
	cout << "众数:" << all.x;
	//clock_t start = clock();
	//for (int i = 0; i < 10000000; i++) {
		//unsigned int x = rng() % 30000 + 1;
		//unsigned int x = rand() % 30000 + 1;
	//}
	//cout << endl << "生成10000000个随机数的速度(ms):" << clock() - start;
	return 0;
}

 

对比一下和mt19937函数,发现不论是均匀分布还是最大值-最小值,rand都要比mt19937差一大截

最后是rand的时间

代码:  

#include <cstdio>
#include <ctime>
#include <iostream>
#include <random>
using namespace std;
int cnt[30050];
struct val {
	int x;//下标
	int y;//数量
}all;
int main() {
	srand(time(0));
	std :: mt19937 rng(time(0));
	//1-5000,5001-10000,10001-15000,15001-20000,20001-25000,25001-30000;
	for (int i = 0; i < 1000000; i++) {
		//unsigned int x = rng() % 30000 + 1;
		unsigned int x = rand() % 30000 + 1;
		if (1 <= x && x <= 5000) cnt[1]++;
		else if (5001 <= x && x <= 10000) cnt[2]++;
		else if (10001 <= x && x <= 15000) cnt[3]++;
		else if (15001 <= x && x <= 20000) cnt[4]++;
		else if (20001 <= x && x <= 25000) cnt[5]++;
		else cnt[6]++;
	}
	cout << "第一个数:1-5000 第二个数:5001-10000 第三个数:10001-15000 第四个数:15001-20000 第五个数:20001-25000 第六个数:25001-30000" << endl;
	cout << cnt[1] << " " << cnt[2] << " " << cnt[3] << " " << cnt[4] << " " << cnt[5] << " " << cnt[6] << endl;
	memset(cnt, 0, sizeof(cnt));
	for (int i = 0; i < 1000000; i++) {
		//unsigned int x = rng() % 30000 + 1;
		unsigned int x = rand() % 30000 + 1;
		cnt[x]++;
	}
	int maxn = -1, minn = 1000050;
	for (int i = 1; i <= 30000; i++) {
		if (cnt[i] > maxn) maxn = cnt[i];
		if (cnt[i] < minn) minn = cnt[i];
	}
	cout << "maxn:在1-30000中出现最多的数,minn:在1-30000中出现最少的数" << endl;
	cout << "maxn - minn = " << maxn - minn << endl;
	long long sum1 = 0, middle, sum2 = 0;
	for (int i = 1; i <= 30000; i++) {
		sum1 += i * cnt[i];
		if (sum2 < 500000 && sum2 + cnt[i] >= 500000) middle = i + 1;
		sum2 += cnt[i];
	}
	double average = (double)sum1 / 1000000.0;
	cout << "平均数:" << average << endl;
	cout << "中位数:" << middle << endl;
	maxn = -1;
	for (int i = 1; i <= 30000; i++) if (cnt[i] > maxn) maxn = cnt[i];
	for (int i = 1; i <= 30000; i++) if (cnt[i] == maxn) all.x = i, all.y = maxn;
	cout << "众数:" << all.x;
	clock_t start = clock();
	for (int i = 0; i < 10000000; i++) {
		//unsigned int x = rng() % 30000 + 1;
		unsigned int x = rand() % 30000 + 1;
	}
	cout << endl << "生成10000000个随机数的速度(ms):" << clock() - start;
	return 0;
}

然后后我们可以得出1个结论,rand比mt19937除了适用性外都差很多

最后介绍一下用法,就是再代码前面加上这样一行代码初始化

std :: mt19937 rng(time(0));

然后再调用rng()就行了,生成的是unsigned int的范围的随机数,如果用int会有负数

具体的就看OIWIKI吧

最后的最后,大家留个赞再走吧

标签: 28zjw印制板连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台