我发现嵌套的
if
比序列化的 if
运行得更快,这让我很困惑。
我有一段代码需要运行1亿次:
if(b8 < 254) {
if(b8 < 252)
return data[b8];
return random_bit() ? data[b8] : -data[b8];
}
b8
是一个 uint8_t
随机数,random_bit()
返回 0-1 随机数。该片段将通过 2 个 if 判断返回一些值,我意识到我可以将其重写为
if(b8 < 252)
return data[b8];
if(b8 < 254)
return random_bit() ? data[b8] : -data[b8];
现在,
return data[b8]
只需要1个if判断。然而,我注意到程序在重复 1 亿次时速度慢了大约 0.01 秒。由于某种原因,我需要这段代码运行得更快,即使它是 0.01 秒。那么我是否误解了这段代码?
顺便说一句,代码是用
-Ofast
编译的,汇编代码对我来说太复杂了,无法理解。汇编代码:
.L2: ; nested
cmpb $-3, %bl
ja .L3
movzbl %bl, %r12d
cmpb $-5, %bl
ja .L4
movsbl sample_val.8(%r12), %ebx
addq $8, %rsp
movl %ebx, %eax
popq %rbx
popq %rbp
popq %r12
popq %r13
ret
.L2: ; serialized
cmpb $-5, %r14b
jbe .L24
movl %r14d, %ebx ; inline random_bit()
movl $8, %r12d
movq cnt.7(%rip), %rdx
movabsq $4611686018427387904, %r13
andl $1, %ebx
cmpb $-3, %r14b
ja .L19
testq %rdx, %rdx
je .L6
shrq %rdx
movq b64.6(%rip), %rax
movq %rdx, cnt.7(%rip)
GCC 只是将它们编译成不同的东西,尽管我认为它们是等效的。
这实际上取决于
b8
的值最常见。该代码区分了三种情况:
b8 < 252
252 <= b8 < 254
b8 >= 254
现在考虑两个版本对每种情况进行的比较次数。
“嵌套”代码执行 (1) 2 次比较 (2) 2 次比较 (3) 1 次比较。
“序列化”代码执行 (1) 1 次比较 (2) 2 次比较 (3) 2 次比较。
因此“嵌套”代码优化了
b8 >= 254
的情况,而“序列化”代码优化了 b8 < 252
的情况。