我必须显示从1
到20
的所有奇数整数:
我的老师说这个循环是错误的,因为它没有逻辑:
int i;
for (i=1;i<=20;i=i+2)
{
cout<<endl<<i;
}
据他说,这是对的:
int i;
for (i=1;i<=20;i++)
{
if (i%2!=0)
{
cout<<endl<<i;
}
}
为什么他说第一个循环是错误的,即使它们都给出相同的结果?
答案 0 :(得分:2)
TL; DR 你的版本在各方面都明显更好:)。您的教师版本循环20次,而您的版本仅循环10次。它的效率提高了100%(即使它被编译器优化掉了,也没有区别)。
注意:在比较中你甚至不需要=
,因为它永远不会是20
,只会更少。
如果您愿意,可以看到生成的装配(非优化)的差异:
您的版本
main:
; Initialization omitted
.LCFI1:
subq $16, %rsp
movl $1, -4(%rbp) ; Initialize 'i' to 1
jmp .L2 ; Jump to compare statements
.L3:
movl -4(%rbp), %eax ; Copy 'i' to register1 (for function call)
; Omitted call to std::cout to output 'i' and '\n'
addl $2, -4(%rbp) ; Add 2 to 'i'
.L2:
cmpl $20, -4(%rbp) ; Compare 'i' to 20
jle .L3 ; Jump only if 'i' < 20
movl $0, %eax ; Reset (cleanup)
leave ; Leave
他的版本
main:
.LCFI1:
subq $16, %rsp
movl $1, -4(%rbp) ; Initialize 'i' to 1
jmp .L2 ; Jump to compare statements
.L4:
movl -4(%rbp), %eax ; Copy 'i' to register1
andl $1, %eax ; XOR 'i' with 1 (same as 'i' % 2)
testl %eax, %eax ; Compares 'i' to 'i'
je .L3 ; Continue loop by jumping if 'i' == 0
; Omitted call to std::cout to output 'i' and '\n'
.L3:
addl $1, -4(%rbp) ; Add 1 to 'i'
.L2:
cmpl $20, -4(%rbp) ; Compare 'i' to 20
jle .L4 ; Jump only if 'i' < 20
movl $0, %eax ; Reset (cleanup)
leave ; Leave
正如您所看到的,您的版本的指令远少于其版本,因此您的版本在非优化代码中运行得更快。
以下是非优化版本的基准
Version | Time
You | 0s
His | 0.015625s
此处为优化(使用-O3
编译)
Version | Time
You | 0s
His | 0s
最后,没有区别,因为编译器非常擅长优化这样的循环。
上面的程序集由Ubuntu 14上的g ++ 4.8.4生成,使用以下命令:g++ -S -fno-asynchronous-unwind-tables -fno-dwarf2-cfi-asm foo.cpp
答案 1 :(得分:0)
第一个代码示例不确定数字是否为奇数。它使用预先存在的知识打印1-20范围内的所有关闭数字。先前存在的知识是,您已经知道数字1,3,5,...是奇数,您只需打印该信息。第二个例子遍历所有数字1-20并计算/确定该范围内的任何数字是否为奇数。意思是,如果它不能被2整除(因此%2运算)那么它就是一个奇数。这就是你的老师所说的。