C 指令级有符号数模

C 指令级有符号数模,c,gcc,assembly,modulus,C,Gcc,Assembly,Modulus,阅读之前关于gcc和clang中的有符号数字模计算的不同实现的有趣讨论,我提出了一个问题(讨论中未讨论) 究竟为什么要实施这一点: if(num%2==1) 从这个开始(在clang和gcc中类似): 为什么我们从((num>>31)+num)开始?为什么要使用MSB并将其添加到数字中?这是从哪里来的?负数%2的结果是负数余数,除法在C中向0取整。&1仅适用于正数 因此,编译器生成代码,将符号位数字相加-实际上是将负数增加1,这样-1在最后一位有0,然后-2在最后一位有1,-3又有0。。。然后,

阅读之前关于
gcc
clang
中的有符号数字模计算的不同实现的有趣讨论,我提出了一个问题(讨论中未讨论)

究竟为什么要实施这一点:

if(num%2==1)

从这个开始(在
clang
gcc
中类似):


为什么我们从
((num>>31)+num)
开始?为什么要使用
MSB
并将其添加到数字中?这是从哪里来的?

负数
%2
的结果是负数余数,除法在C中向0取整。
&1
仅适用于正数

因此,编译器生成代码,将符号位数字相加-实际上是将负数增加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个延迟和吞吐量,我怀疑您是否启用了优化。一般来说,这是为了处理负数的舍入,但是
%2
应该优化为
&1
@jester
&1
不适用于负数的模。啊,是的,忘记了C模给出负余数。无论如何,MSB是符号位。这样就可以处理底片了。您需要查看完整的代码,看看它是如何影响结果的。“可能稍微”是一个大大的轻描淡写。它的延迟不到1/3,如果重复使用,吞吐量可能是7倍,因此分配器将成为瓶颈。(如果只是普通前端uop吞吐量是瓶颈,而不是未管道分隔器,则为吞吐量的~两倍。)
movl    %edi, %edx
shrl    $31, %edx
leal    (%rdi,%rdx), %eax
andl    $1, %eax
subl    %edx, %eax