有人可以解释一下这些表达式之间相当大的性能差异吗?我希望这些表达式可以提供相似的性能。我正在发布模式下使用Apple LLVM版本5.1(clang-503.0.38)(基于LLVM 3.4svn)进行编译。
这是我的测试代码(只需将CASE更改为1,2,3或4进行自我测试):
#include <iostream>
#include <chrono>
#define CASE 1
inline int foo(int n) {
return
#if CASE == 1
(n % 2) ? 9 : 6
#elif CASE == 2
(n % 2) == true ? 9 : 6
#elif CASE == 3
6 + (n % 2) * 3
#elif CASE == 4
6 + bool(n % 2) * 3
#endif
;
}
int main(int argc, const char* argv[])
{
std::chrono::time_point<std::chrono::system_clock> start, end;
start = std::chrono::system_clock::now();
int n = argc;
for (int i = 0; i < 100000000; ++i) {
n += foo(n);
}
end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end-start;
std::cout << "elapsed time: " << elapsed_seconds.count() << "\n";
std::cout << "value: " << n << "\n";
return 0;
}
以下是我得到的时间:
CASE EXPRESSION TIME
1 (n % 2) ? 9 : 6 0.1585
2 (n % 2) == true ? 9 : 6 0.3491
3 6 + (n % 2) * 3 0.2559
4 6 + bool(n % 2) * 3 0.1906
以下是CASE 1和CASE 2之间装配的不同之处:
案例1:
Ltmp12:
LBB0_1: ## =>This Inner Loop Header: Depth=1
##DEBUG_VALUE: main:argv <- RSI
##DEBUG_VALUE: i <- 0
.loc 1 24 0 ## /Test/main.cpp:24:0
movl %ebx, %ecx
andl $1, %ecx
leal (%rcx,%rcx,2), %ecx
Ltmp13:
.loc 1 48 14 ## /Test/main.cpp:48:14
leal 6(%rbx,%rcx), %ebx
案例2:
Ltmp12:
LBB0_1: ## =>This Inner Loop Header: Depth=1
##DEBUG_VALUE: main:argv <- RSI
##DEBUG_VALUE: i <- 0
.loc 1 24 0 ## /Test/main.cpp:24:0
movl %ebx, %ecx
shrl $31, %ecx
addl %ebx, %ecx
andl $-2, %ecx
movl %ebx, %edx
subl %ecx, %edx
cmpl $1, %edx
sete %cl
movzbl %cl, %ecx
leal (%rcx,%rcx,2), %ecx
Ltmp13:
.loc 1 48 14 ## /Test/main.cpp:48:14
leal 6(%rbx,%rcx), %ebx
这是CASE 3和CASE 4之间装配的不同之处:
案例3:
Ltmp12:
LBB0_1: ## =>This Inner Loop Header: Depth=1
##DEBUG_VALUE: main:argv <- RSI
##DEBUG_VALUE: i <- 0
.loc 1 24 0 ## /Test/main.cpp:24:0
movl %ebx, %ecx
shrl $31, %ecx
addl %ebx, %ecx
andl $-2, %ecx
movl %ebx, %edx
subl %ecx, %edx
leal (%rdx,%rdx,2), %ecx
Ltmp13:
.loc 1 48 14 ## /Test/main.cpp:48:14
leal 6(%rbx,%rcx), %ebx
案例4:
Ltmp12:
LBB0_1: ## =>This Inner Loop Header: Depth=1
##DEBUG_VALUE: main:argv <- RSI
##DEBUG_VALUE: i <- 0
.loc 1 24 0 ## /Test/main.cpp:24:0
movl %ebx, %ecx
andl $1, %ecx
negl %ecx
andl $3, %ecx
Ltmp13:
.loc 1 48 14 ## /Test/main.cpp:48:14
leal 6(%rbx,%rcx), %ebx
答案 0 :(得分:4)
这个答案目前仅涵盖前两种情况之间的差异。
(n % 2)
的可能值是多少?当然,它是0
和1
,对吧?
错误。它是0
,1
和 -1
。因为n
是有符号整数和the result of %
can be negative。
(n % 2) ? 6 : 9
隐式将表达式n % 2
转换为bool
。此转化的结果是true
IFF值非零。因此,转化等同于(n % 2) != 0
。
在(n % 2) == true ? 6 : 9
中,对于比较(n % 2) == true
,通常的算术转换应用于双方(请注意bool
是算术类型)。 true
被提升为值int
的{{1}}。因此,转化等同于1
。
两次转化(n % 2) == 1
和(n % 2) != 0
会产生负面(n % 2) == 1
的不同结果:设n
。然后n = -1
和n % 2 == -1
为-1 != 0
,true
为-1 == 1
。
因此,编译器必须引入一些额外的复杂性来处理符号。
如果您将false
设为无符号整数,或者以任何其他方式移除符号问题(例如,通过比较n
),运行时间的差异就会消失。
我通过查看程序集输出得到了这个想法,尤其是以下行:
n % 2 != false
首先使用最高位对我没有意义,直到我意识到最高位被用作符号。