阅读 this前段时间关于 gcc
和 clang
中signed 数模计算的不同实现的有趣讨论向我提出了一个问题(在讨论)。
到底为什么要执行这个:
if(num % 2 == 1)
以此开头(在 clang
和 gcc
中类似):
movl %edi, %eax
shrl $31, %eax
addl %edi, %eax
为什么我们从 ((num >> 31) + num)
开始?为什么取 MSB
并将其添加到号码中?这是从哪里来的?
最佳答案
负 % 2
的结果是负余数,在 C 中除法向 0 舍入。& 1
仅适用于正数。
因此编译器生成添加符号位数的代码 - 本质上是将负数增加一位,因此 -1
在最后一位中具有 0
,然后 -2
在最后一位有 1
,-3
又有 0
... 然后我们屏蔽掉除了最后一位,从结果中减去符号位,例如:
movl %edi, %edx
shrl $31, %edx
leal (%rdi,%rdx), %eax
andl $1, %eax
subl %edx, %eax
它的性能可能比 idiv
指令稍微好一点。例如,在 Core i7 上,具有 r32 的 IDIV 将具有 17-28 的延迟和 7-12 的吞吐量,而生成的代码中的所有其他代码都具有 ~1
关于c - 指令级的有符号数模数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52933729/