【(2019/11/18更新第二部分)简单(娱乐向?)测试】cstdlib 中的 rand() 和 C++11 起新增的 random 头文件,哪个生成随机整数更快?

210 篇文章 9 订阅
36 篇文章 0 订阅
本文对比了C++11的<random>头文件与cstdlib中的rand()函数在生成随机整数的速度上进行测试。在Release模式下,C++11的random头文件表现更快,而在Debug模式下较慢。测试还涵盖了不同编译器、随机数范围和优化选项的影响,揭示了在不同场景下的最佳实践。
摘要由CSDN通过智能技术生成

今天在折腾Miller Rabin算法和Pollard Rho算法,中间过程要求随机数。于是来验证一下哪种方法更快生成随机数。

反正就是编一个随机整数生成的函数,每调用一次生成一个,参数分别是下界和上界。生成1e7个unsigned long long类型的随机数,并存入变量a。
二话不说,上代码。

#include<cstdio>
#include<cstdlib>
#include<chrono>
#include<random>
#pragma warning(disable:4996)
std::default_random_engine D;
template<typename _Ty> inline _Ty randbetween(const _Ty& a, const _Ty& b) {
	if (b < 1 << 15)return (rand() + a) % b;
	else if (b < 1 << 30)return ((rand() << 15) + rand() + a) % b;
	else if (b < (_Ty)1 << 45)return (((_Ty)rand() << 30) + (rand() << 15) + rand() + a) % b;
	else if (b < (_Ty)1 << 60)return (((_Ty)rand() << 45) + ((_Ty)rand() << 30) + (rand() << 15) + rand() + a) % b;
	return (((_Ty)rand() << 60) + ((_Ty)rand() << 45) + ((_Ty)rand() << 30) + (rand() << 15) + rand() + a) % b;
}
template<typename _Ty> inline _Ty RandBetween(const _Ty& a, const _Ty& b) {
	std::uniform_int_distribution<_Ty> U(a, b);
	return U(D);
}
template<typename _Ty> inline _Ty randfrom(const _Ty& a, const _Ty& b) {
	return (((_Ty)rand() << 60) + ((_Ty)rand() << 45) + ((_Ty)rand() << 30) + (rand() << 15) + rand() + a) % b;
}
int main() {
	srand(std::chrono::steady_clock::now().time_since_epoch().count());
	clock_t t1, t2, t3; unsigned long long a;
	_sleep(5000);
	t1 = clock();
	for (unsigned long long i = 0; i < 10000000; ++i)
		a = randbetween(0ull, (unsigned long long) - 1);
		//printf("%llu\n", randbetween(0ull, (unsigned long long) - 1));
	t1 = clock() - t1;
	t2 = clock();
	for (unsigned long long i = 0; i < 10000000; ++i)
		a = RandBetween(0ull, (unsigned long long) - 1);
		//printf("%llu\n", RandBetween(0ull, (unsigned long long) - 1));
	t2 = clock() - t2;
	t3 = clock();
	for (unsigned long long i = 0; i < 10000000; ++i)
		a = randfrom(0ull, (unsigned long long) - 1);
		//printf("%llu\n", randfrom(0ull, (unsigned long long) - 1));
	t3 = clock() - t3;
	printf("\n%d %d %d\n", t1, t2, t3);
	getchar();
	return 0;
}

上结果:
run time记录的值从上到下分别是t1 t2 t3。

结论:
1、Release模式下,明显用头文件random产生随机数更快。Debug模式下更慢,不知道什么原因。
无论是比赛还是正式发布你的软件,肯定是用release版本的代码,所以首选random头
2、t1和t3基本没区别,可以看出if else条件语句其实不费多少时间。
3、试了一下,GCC编出来的代码的printf输出比MSVC的要慢很(就是把三个for循环体下面的第一句都注释掉,换成第二句,无论是Debug模式还是Release模式下都慢得多,GCC跑出来约13s 10s 10s,Debug和Release都是这样,MSVC跑出来Debug是大约3s 0.6s 0.6s,Release下快近20%吧)多,不知道为何。

当随机整数的范围在[0, 32767]之间时,rand()和通过random头文件生成随机数的耗时对比。
代码:

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<random>
#include<ctime>
#pragma warning(disable:4996)
const unsigned long long TestQty = 10000000;
std::default_random_engine D;
std::uniform_int_distribution<int> U(0, 32767);
template<typename _Ty> inline _Ty RandBetween(const _Ty& a, const _Ty& b) {
	std::uniform_int_distribution<_Ty> U(a, b);
	return U(D);
}
int main() {
	clock_t t1, t2, t3; int a; srand(time(0)); D.seed(time(0));
	_sleep(5000);
	t1 = clock();
	for (unsigned long long i = 0; i < TestQty; ++i)
		a = rand();
	t1 = clock() - t1;
	t2 = clock();
	for (unsigned long long i = 0; i < TestQty; ++i)
		a = U(D);
	t2 = clock() - t2;
	t3 = clock();
	for (unsigned long long i = 0; i < TestQty; ++i)
		a = RandBetween(0, 32767);
	t3 = clock() - t3;
	printf("%d %d %d\n", t1, t2, t3);
	system("pause");
	return 0;
}

经实测,局部的

std::uniform_int_distribution<_Ty> U(a, b);

前是否添加static修饰几乎不影响运行速度,但机理不明。
实验结果如下(每列的从上到下分别为t1、t2、t3,单位ms):
在这里插入图片描述结论:
1、VS的Debug模式不知道增加了多少东西,使得通过random头生成随机数的耗时大大增加。
2、无论是发布你的正式版软件,还是比赛交题,肯定都是生成Release代码。而Release模式下,如果是MSVC编出来的代码,方案三即局部建立随机分布并返回值是最快的,但原理也未知。
GCC(G++)编出来的代码中,方案二和方案三两者的运行时间几乎没有区别。而Debug模式下,运行速率均为:方案一 > 方案二 > 方案三。
3、考虑到Linux下RAND_MAX的常量宏的值为4294967295而非Windows下的32767。笔者目前未安装Linux系统,故暂时不予测试。但也给出方案二和方案三在上界分别为2147483647、4294967295(此时随机分布需要构造unsigned类型)的条件下的运行耗时。
以下结果,统一左边为VS2019,MSVC编译器;右边为Codeblocks 17.12,GCC 9.2编译器,编译选项为-O2 -m64 -std=c++1z。
在这里插入图片描述
(边界为[0, 2147483647],整数均匀分布为int类型,Debug模式)
在这里插入图片描述
(边界为[0, 4294967295],整数均匀分布为unsigned类型,Debug模式)
在这里插入图片描述
(边界为[0, 2147483647],整数均匀分布为int类型,Release模式)
在这里插入图片描述
(边界为[0, 4294967295],整数均匀分布为unsigned类型,Release模式)
晚上在宿舍的时候补测两组:
在这里插入图片描述
(边界为[0, 2147483647],整数均匀分布为unsigned类型,Debug模式)
在这里插入图片描述
(边界为[0, 2147483647],整数均匀分布为unsigned类型,Release模式)
虽然晚上跑的这两组不知道为什么方案二和三慢了那么几到十几ms,但是仍然可以看出来,当std::uniform_int_distribution<>的边界从[0, 2147483647]变成[0, 4294967295]时,生成随机数的速率反而会变快。当然背后的原因也是不清楚的,真的很玄学。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值