我有以下两个循环:
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
int main(){
int start=clock();
for (int i=0;i<100;i++)
cout<<i<<" "<<endl;
cout<<clock()-start<<"\n"<<endl;
cout<<"\n";
int start1=clock();
for (int j=0;j<100;++j)
cout<<j<<" "<<endl;
cout<<"\n";
cout<<clock()-start1<<" \n "<<endl;
return 0;
}
我跑了三次。在前两次运行中,第二次循环最快,但在第三次运行时,第一次循环最快。这是什么意思?哪个更好?这取决于具体情况吗?
答案 0 :(得分:10)
循环的运行时间绝大部分由输入输出操作决定。这意味着您观察到的时间1)与循环的实际性能无关(即i++
vs ++j
),2)几乎是不可预测和不稳定的(基本上是随机的)。
换句话说,你的实验毫无意义。它绝对没有意义。
最后,在不使用内置++
运算符的结果的情况下,后缀和前缀增量之间绝对没有区别。在任何合理的编译器中,两个循环都将具有完全相同的性能。
答案 1 :(得分:5)
在您的情况下,它可能是标准测量误差,您使用后增量或预增量无关紧要。对于标准类型(int,byte ...),这没关系。
但您应该习惯使用预增量,因为如果您在类上使用它们会对性能产生影响,具体取决于这些运算符的实现方式。后增量运算符i ++必须复制对象
例如:
class integer
{
public:
integer(int t_value)
: m_value(t_value)
{
}
int get_value() { return m_value; }
integer &operator++() // pre increment operator
{
++m_value;
return *this;
}
integer operator++(int) // post increment operator
{
integer old = *this; // a copy is made, it's cheap, but it's still a copy
++m_value;
return old; // Return old copy
}
private:
int m_value;
看看以下答案
StackOverflow: i++ less efficient than ++i, how to show this?
答案 2 :(得分:4)
这些循环对于int类型的归纳变量是等效的。这里已经多次回答了后增量与预增量问题。尝试稍微搜索一下档案。
此外,与标准IO相比,增量操作只需要一小部分时间。您的测试是测量IO的速度而不是增量操作的速度。
答案 3 :(得分:3)
旧GCC 3.4.4执行此操作:
第一次循环:
.L11:
cmpl $99, -8(%ebp)
jg .L12
subl $8, %esp
pushl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
subl $12, %esp
pushl $.LC0
subl $12, %esp
pushl -8(%ebp)
pushl $_ZSt4cout
.LCFI7:
call _ZNSolsEi
addl $20, %esp
pushl %eax
call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
addl $20, %esp
pushl %eax
.LCFI8:
call _ZNSolsEPFRSoS_E
addl $16, %esp
leal -8(%ebp), %eax
incl (%eax)
jmp .L11
.L12:
第二次循环:
.L14:
cmpl $99, -12(%ebp)
jg .L15
subl $8, %esp
pushl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
subl $12, %esp
pushl $.LC0
subl $12, %esp
pushl -12(%ebp)
pushl $_ZSt4cout
.LCFI13:
call _ZNSolsEi
addl $20, %esp
pushl %eax
call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc
addl $20, %esp
pushl %eax
.LCFI14:
call _ZNSolsEPFRSoS_E
addl $16, %esp
leal -12(%ebp), %eax
incl (%eax)
jmp .L14
.L15:
你能找到任何差异吗? :)(除了我和j在堆栈上的不同位置-8(%ebp)和-12(%ebp))
答案 4 :(得分:1)
这意味着您应该使用统计技术来确定哪个循环更快(我希望这些技术确定它们彼此相当不同)。
你没有知道你的CPU正在做什么,而不是你把它放在这里的负载。
它可能会启动计划任务,处理中断,各种会扭曲结果的事情。
您可能需要进行一百万次运行,抛弃异常值,并对其余值进行平均以得到合适的样本。
最重要的是,一百次迭代并不多,特别是因为你正在对cout
进行函数调用,这可能沼泽进行循环控制所花费的时间。
当我在UNIX下运行检查时,由于这个原因,我不使用已用时间。无论经过的时间如何,系统和用户时间都会给出给定进程使用CPU的秒数。
答案 5 :(得分:1)
++我应该得到与i ++相同的机器代码,并且在任何中途正常的编译器上使用未使用的结果(前提是它没有以一种奇特的方式过载,这不是int的情况)。即使它没有(你需要从上个世纪挖出一个非常愚蠢的编译器),差异是如此之小,你永远不必担心它。好吧,有些情况下你确实需要从中挤出一小部分性能,但是我们每个人都会遇到这种情况。即使这样,循环体也有更多的优化潜力(即使在你过于简单的例子中 - I / O比复制机器字更加省钱)。
或者用一句话说:过早优化是万恶之源。
答案 6 :(得分:1)
从我看到的,循环中唯一的区别是循环变量的前/后增量。大部分处理时间将花在cout上。相比之下,增量的时间可以忽略不计。
答案 7 :(得分:-1)
++我是preincrement
i ++是postincrement
有关详细信息,请参阅Operator