当值加倍时,加法与乘法与左移操作[重复]
Posted
技术标签:
【中文标题】当值加倍时,加法与乘法与左移操作[重复]【英文标题】:Addition vs multiplication vs shift left operation when double the value [duplicate] 【发布时间】:2019-03-22 06:11:11 【问题描述】:假设一个数字具有非常大的值,例如 9,046,744,073,709,551,615。
我使用加法、乘法和左移将值加倍。
#include <iostream>
using namespace std;
int main()
unsigned long long int value = 9046744073709551615;
cout << (value + value) << endl;
cout << (value * 2) << endl;
cout << (value << 1) << endl;
return 0;
哪个计算得更快?
【问题讨论】:
为什么不检查编译器的汇编输出并启用优化?您可能会发现每一个都转换为相同的代码。 编译器在微优化方面比人类要好得多。使用在代码上下文中有意义的那个。 (在这种特殊情况下,任何体面的编译器都会在编译时执行每个操作并打印一个常量。) 为什么你认为数字的大小很重要? value is hardcoded 或read at runtime 时,每种情况下的优化程序集相同。 Steve Maguire,“Writing Solid Code”,1993 年:“多年来,我发现了程序员使用移位来划分不能保证为正的有符号值的错误。我已经追踪了程序员转向错误方向的错误。我什至追踪了程序员通过不小心将表达式如 a=b+c/4 转换为 a=b+c>>2 而引入优先级错误的错误。我不知道不记得曾经追踪过一个错误,其中程序员打算除以 4 并在输入字符 / 和 4" 时出错 【参考方案1】:简短的回答是,没有一个替代方案更快。当启用编译器优化时,它们会生成相同的代码。
对于在编译时知道值的情况,程序集是这样的:Compiler Explorer link
movabs rsi, -353255926290448386
call std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<unsigned long long>(unsigned long long)
它将一个常量加载到一个寄存器中并调用operator<<()
。所有三种备选方案都会产生这种优化的装配体。
对于在运行时读取值的情况,程序集是这样的:Compiler Explorer link
mov rax, QWORD PTR [rsp+8]
mov edi, OFFSET FLAT:_ZSt4cout
lea rsi, [rax+rax]
call std::basic_ostream<char, std::char_traits<char> >& std::basic_ostream<char, std::char_traits<char> >::_M_insert<unsigned long long>(unsigned long long)
它使用加法 (rax+rax
) 并调用 operator<<()
。同样,所有三个备选方案都产生相同的程序集。
【讨论】:
【参考方案2】:我刚刚从godbolt 中挑选了一个编译器。确实完全没有区别。玩转编译器和优化级别。
在-O0
中使用 x86-64_gcc 会产生 3 倍的结果:
mov rax, QWORD PTR [rbp-8]
add rax, rax
mov rsi, rax
mov edi, OFFSET FLAT:_ZSt4cout
call std::basic_ostream<char, std::char_traits<char> >::operator<<(unsigned long long)
mov esi, OFFSET FLAT:_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_
mov rdi, rax
call std::basic_ostream<char, std::char_traits<char> >::operator<<(std::basic_ostream<char, std::char_traits<char> >& (*)(std::basic_ostream<char, std::char_traits<char> >&))
【讨论】:
以上是关于当值加倍时,加法与乘法与左移操作[重复]的主要内容,如果未能解决你的问题,请参考以下文章