我正在学习c / c ++代码优化。编写一个简单的for循环程序,for循环的哪一部分将比其他w.r.t<<和*运算符。下面的代码片段。
x
答案 0 :(得分:3)
首先,这是使用乘法运算符的程序集(我添加了注释):
.LC0:
.string " "
main:
pushq %rbp
movl $10, %ebp // Part of loop
pushq %rbx
movl $1, %ebx // Part of loop
subq $8, %rsp
.L2:
movl %ebx, %esi
movl std::cout, %edi
addl %ebx, %ebx // Part of loop
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
movl $1, %edx
movl $.LC0, %esi
movq %rax, %rdi
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
subl $1, %ebp // Part of loop
jne .L2 // Part of loop
addq $8, %rsp
xorl %eax, %eax
popq %rbx
popq %rbp
ret
subq $8, %rsp
movl std::__ioinit, %edi
call std::ios_base::Init::Init()
movl $__dso_handle, %edx
movl std::__ioinit, %esi
movl std::ios_base::Init::~Init(), %edi
addq $8, %rsp
jmp __cxa_atexit
这是使用移位运算符的程序集:
.LC0:
.string " "
main:
pushq %rbp
movl $10, %ebp
pushq %rbx
movl $1, %ebx
subq $8, %rsp
.L2:
movl %ebx, %esi
movl std::cout, %edi
addl %ebx, %ebx
call std::basic_ostream<char, std::char_traits<char> >::operator<<(int)
movl $1, %edx
movl $.LC0, %esi
movq %rax, %rdi
call std::basic_ostream<char, std::char_traits<char> >& std::__ostream_insert<char, std::char_traits<char> >(std::basic_ostream<char, std::char_traits<char> >&, char const*, long)
subl $1, %ebp
jne .L2
addq $8, %rsp
xorl %eax, %eax
popq %rbx
popq %rbp
ret
subq $8, %rsp
movl std::__ioinit, %edi
call std::ios_base::Init::Init()
movl $__dso_handle, %edx
movl std::__ioinit, %esi
movl std::ios_base::Init::~Init(), %edi
addq $8, %rsp
jmp __cxa_atexit
完全相同(我只使用-O3
使用GCC 5.3 for x86编译,因此其他编译器和其他体系结构可能不是这样。)
在查看Chris评论中发布的链接后,自动突出显示似乎移位操作员需要其他说明:
subl $1, %ebp
jne .L2
movl $10, %ebp // Actually not part of loop
movl $1, %ebx // Actually not part of loop
与乘法相比,即:
subl $1, %ebp
jne .L3
这与我发布的原始程序集不同(因为两者完全相同)。
如Revolver_Ocelot的评论中所述,说明
movl $10, %ebp
movl $1, %ebx
只是为下一个循环设置计数器,因此循环组件实际编译为相同的程序集(对于此编译器和体系结构),如单独的比较所示。
更新:根据Flikk的评论说会议将有所不同,这里是unoptimised version,表明它们是相同的。
答案 1 :(得分:1)
您正在尝试微观优化。当我开始说这是初学者节省微秒,真正的程序员节省了几毫秒。如今初学者可以节省纳秒,真正的程序员可以节省微秒: - )
您正在输出我到std :: cout。那时,我如何计算所以完全不相关,因为输出需要几千倍的时间。
现在让我们来看看程序的功能。在某些时候,您会遇到溢出,这会给您未定义的行为,这意味着任何都可能发生。正确的程序比快速程序重要数千倍。因此,当您的代码已经破坏时,任何优化尝试都是毫无意义的。
现在让我们来看看你在做什么。问问自己:编译器是否弄清楚你在做什么?编译器显然会看到每个变量将i乘以2.编译器将使用以最快的方式将i乘以2 ,无论方法是什么。可能会把我添加到自己:-)所以你正在做的事情再次毫无意义;编译器比这更聪明。
回到微观优化:它们完全无效,因为编译器在微优化方面比你好十倍。真正的程序员不会试图让操作变得更快;他们开发的数据结构和算法开始时需要的操作少得多!他们首先测量以找出需要时间的内容并优化其计数的位置,而不是尝试优化随机位。然后他们会测量是否有任何优化尝试确实有效。
答案 2 :(得分:0)
我可以给你一个简单的想法,它可以帮助你判断i * = 2和i = i&lt;&lt; 1之间哪个更快。
更新MAX = 10 18 并使用long long int作为数据类型。现在使用time()函数独立测量两个for循环的运行时间。并找出运行时间的差异。
注意:由于最多会有60次迭代,因此运行时间的差异可能无法比较,因此在这种情况下您可以使用BigInteger库。
结果:位操作更快。