当它们都正常工作时,为什么只有以下代码之一?

时间:2016-05-16 07:03:03

标签: c++

我必须显示从120的所有奇数整数:

我的老师说这个循环是错误的,因为它没有逻辑:

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;
    }
}

为什么他说第一个循环是错误的,即使它们都给出相同的结果?

2 个答案:

答案 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运算)那么它就是一个奇数。这就是你的老师所说的。