实测!!论如何在OI赛场上提高程序运行速度
摘要:其实register、inline和读入优化大多数情况下并没有什么卵用,,
目录:
1.引子
2.实验机基本信息
3.inline关键字测试
4.register关键字测试
5.cin、scanf、快读三种读入方式的比较
6.附:for循环中++i与i++两种写法的速度测试
7.总结
引子:
据说变量前面加个register
以及函数前面加个inline
以及写个读优啥的
(PS:我知道我很弱请不要吐槽我的读优)
能够提高程序运行速度!!
天真的我竟然相信了!!
于是养成了一些不好的习惯,比如变量前面顺手加个register,函数前面顺手加个inline以及顺手写个读优啥的……
于是遭到了诸如hzwDL和szjDL的嘲讽……
所以,rigister、inline和读优到底有没有用呢??
今天我们一起来做一个实验!!!!!
--------------------------华丽的分割线--------------------------
实验机基本信息:
测试系统:Mac OS
型号:MacBook Air 7, 2
处理器:Inter Core i5 双核 1.6GHz
L2:256KB L3:3MB
运存:8GB
inline关键字测试
inline是什么东西?据说是内联函数。
我管他是什么,我只需要知道他快不快就行了。
那我们就找一个函数做实验吧。比如……用快读函数做实验怎么样??
我们首先随机生成一个数据规模一个亿的测试数据。
妈耶……竟然1.5个G,不可思议……
码一个快读。
测试!还行,总用时1min3.744s(运行的时候我还以为我电脑死了)
那么接下来我们加一个inline
1min3.878s!呵呵哒!似乎更慢了!
这是神马情况????
于是查了一下百度百科……据说直接用inline的话,编译器不会鸟你,你需要在头文件里声明一下……
我写的程序编译的时候竟然还要看编译器心情??
行吧,你说啥就是啥。那我就在前面声明一下。
运行!!!!!
窝草!!!!!奇迹发生了!!!竟然快了1秒!!!!
看来inline还是有那么一点用的。
但是inline在任何时候都有用吗????
我们在写一个简单的函数试一试。先不加inline。
为了让实验效果更明显,我们把循环次数加到10个亿。
这个函数可以说是已经简单地不能再简单了。
测试!
2.4s,还行。
那么加inline呢??吸取读优的经验,先在前面声明一下
足足慢了0.2毫秒!!!
实验结果 | 实验1 | 实验2 |
不加inline | 1min3.744s | 2.498s |
加inline,不声明 | 1min3.878s | —— |
加inline,并声明 | 1min2.432s | 2.677s |
小结:看来inline这个东西还是挺玄学的,读优用用就算了,其他函数还是别随便加了,免得帮倒忙。
register关键字测试:
register是什么?据说是强调变量将被频繁使用,央求CPU在运行的时候把这个变量放到寄存器里,以加快后期的访问速度。
你是谁啊,CPU凭啥鸟你啊
为了实验更加简单,我们直接用for循环测试吧。
为了实验效果更加明显,我们直接上一个一百亿的大循环。
其实我一开始用的是int,结果硬是半天跑不完。后来才意识到int类型已经溢出变成负数了……
运行。
还行,用了23秒。
那么我们把register加上。
屁用没有,还更慢了!
实验结果 | 实验1 |
不加register | 23.370s |
加register | 23.455s |
小结:你要是觉得register好看你就加吧,反正他并没有什么用。因为CPU并不想鸟你。
cin、scanf和快读三种读入方式的比较
我们依然使用刚才生成的test.in文件
为了cin不会被虐的太惨,这次我们只读入前一千万个数据。
首先是被很多人嫌弃的cin。让我们来共睹他的风采。
用时44秒。不错,数字很吉利。已经预示了他的结局。
接下来是编者最喜欢的scanf
用时2.2秒,完虐cin!!!!
那么接下来……有请大名鼎鼎的快读……
结果还用问吗,肯定完虐scanf啊
六秒???开玩笑吗??快读你也太不给力了吧!!??
不行不行。快读怎么能输呢……
让我们来分析一下原因
可能是由于数据时随机生成的,数字普遍较大,位数较多。而快读是逐位读取,这样无形之中常数会变得很大
这样吧,我们重新生成一个数据,让所有数字大小均在100以内。
硬盘瞬间腾出一个G的内存
这次我们只生成一千万规模的数据
这样常数就应该小很多了吧
这次我们只比较scanf和快读。(cin已经没有可比性了)
我们先来看scanf
用时1.9秒,还行
那么快读呢????(快读给力一点啊)
呵 呵 哒
实验结果 | 实验1 | 实验2 |
cin | 44.248s | —— |
scanf | 2.220s | 1.939s |
快读 | 6.259s | 2.588s |
小结:同志们,别指望快读了。快乖乖用scanf吧。
附:for循环中++i与i++两种写法的速度测试:
++i和i++的区别相信大多数码农都知道。++i是先加后赋值,i++是先赋值后加。
但是对于for循环中的++i或者i++似乎并没有什么区别,因为他并不需要赋值。
那么在速度上他们有区别吗?
还真有!!!
据说,在执行程序的时候,++i是直接把变量+1,而i++需要先把变量i复制到另一个内存空间,在另一个内存空间中+1,然后再复制回来。所以,理论上++i是比i++要快的。
呵呵哒,inline和register理论上加了还比不加快呢
为了验证理论和现实的差距,我们一起来实践一下
我们来一个十亿的for循环,先看++i的
然后是i++
确实快了一丢丢,但是差别并不是很大。
小结:真正赛场上for循环中的++i和i++其实都差不多,++i虽然比i++快一点点,但就这么一点数据规模看不出什么太大的优势。
总结:
实验做完了,总结一下吧。
多数情况下不加inline比加inline快。
register加上屁用没有,还增加代码量。
scanf战胜了cin和快读。
for循环中++i比i++稍快一点点。
当然,我做的实验违反了多次实验的原则,各位可以在线下做一做这个无聊的实验
所以,oi赛场上如何提高程序运行速率??
踏实写代码,别搞花里胡哨的东西!
其实主要看人品。
本文章为原创,转载请注明出处。