C如何在内部执行%操作
我很想了解mod操作背后的逻辑,因为我知道可以执行位移位操作来做不同的事情,比如位移位乘法 我可以看到的一种方法是使用递归算法,该算法一直进行除法,直到无法再除法为止,但这似乎并不有效C如何在内部执行%操作,c,modulo,C,Modulo,我很想了解mod操作背后的逻辑,因为我知道可以执行位移位操作来做不同的事情,比如位移位乘法 我可以看到的一种方法是使用递归算法,该算法一直进行除法,直到无法再除法为止,但这似乎并不有效 任何想法都会有帮助。提前谢谢 虽然大多数C实现在具有除法指令的硬件上运行,但对于计算p%q,假定无符号值,余数操作大致可以这样执行: #define HI (-1U-(-1U/2)) unsigned i; for (i=0; !(HI & (q<<i)); i++); do { if (p
任何想法都会有帮助。提前谢谢 虽然大多数C实现在具有除法指令的硬件上运行,但对于计算
p%q
,假定无符号值,余数操作大致可以这样执行:
#define HI (-1U-(-1U/2))
unsigned i;
for (i=0; !(HI & (q<<i)); i++);
do { if (p >= (q<<i)) p -= (q<<i); } while (i--);
#定义HI(-1U-(-1U/2))
未签名的i;
对于(i=0;!(HI&(q),除了硬件指令和使用移位的实现之外,还有
当%
的右侧是一个常量,在编译时已知时,可以使用此技术。
倒数乘法用于实现除法,但将其用于%
很容易,根据公式a%b==a-(a/b)*b
快速版本是:取决于硬件、优化器(pdf)、是否有要检查的异常(例如,0的模)、负数是否处理以及如何处理(),等等
对于无符号整数,R给出了一个很好的简明答案,但除非你精通C,否则很难理解
由R照亮的技术的关键是去除q
的倍数,直到不再剩下q
的倍数。我们可以通过简单的循环天真地做到这一点:
while (p >= q) p -= q; // One liner, woohoo!
代码可能很短,但对于p的大值和q的小值,这可能需要很长时间
一次剥离一个q
比一次剥离多个q
要好。请注意,我们实际上希望剥离尽可能多的q
,即楼层(p/q)
许多q
…事实上,这是一种有效的技术。对于无符号整数,可以预期p%q==p-(p/q)*q
(请注意,无符号整数除法向下舍入。)
但这几乎像是作弊,因为除法和余数运算是如此密切相关(事实上,如果硬件本机支持除法,它通常支持除法和计算余数运算,因为它们是如此密切相关)
假设我们无法使用除法,我们如何找到大于1的倍数来去除?在硬件中,固定移位操作很便宜(如果实际上不是免费的话),概念上表示乘以2的非负幂。例如,将一个位字符串左移3等于乘以8(也就是说,2^3),例如,5 decimal相当于'101'二进制。通过在右侧添加三个零(给出'101000')来移动二进制中的'101',结果是十进制中的50,即5乘以8
类似地,轮班操作作为软件操作非常便宜,您很难快速找到不支持它们的控制器(一些体系结构,如ARM,甚至可以将轮班和其他指令结合起来,使它们在很大程度上“免费”)
武装(无法抵抗)这些轮班操作,我们可以如下进行:
求出两个的最大幂,我们可以乘以q
,但仍然小于p
从2的最大幂到最小,将q
乘以2的每一次幂,如果小于p的剩余值,则从p的剩余值中减去它
剩下的就是剩下的了
为什么会这样呢?因为最终你会发现,2的所有减法幂实际上相加为下限(p/q)
!不要相信我的话,类似的知识在一段时间内就已经为人所知了
分解R的答案:
#define HI (-1U-(-1U/2))
这实际上为您提供了一个只设置了最高值位的无符号整数
unsigned i;
for (i=0; !(HI & (q<<i)); i++);
无符号i;
对于(i=0;!(HI&(q取决于优化器的智能,有一个模基2的快捷方式。例如,a%32
可以实现为a&31
。通常,a%(2^N)==a&(2^N-1)
。与除法相比,这是闪电般的快。大多数除法器(任何硬件)计算结果的每一位至少需要1个周期,而逻辑和运算只是几个周期(在管道中)
编辑:这仅在a
无符号时有效!通常,*div
指令在两个寄存器中给出商和余数。只需获取余数。取决于平台。在大多数现代处理器上,都有div
指令(或等效指令)这是直接在硬件中实现的。你可以用c编写一个简单的程序,然后运行gcc-S simple_program.c来查看汇编输出。按照链接,可以得到一个实际的说明。正如其他人所说,这通常是在硬件指令中完成的。但是从算法的角度来看,请看这个:+1这正是我想要的写这篇文章是为了补充我的回答,如果我想花那么多时间在上面的话。:-)我想你的意思是a%b==a-(a/b)*b
。如果你正在做a%256
或a%65536
,这会比使用cast更快:a%256==(uint8 t)a
,a%65536==(uint16)a
(使用)不幸的是,从C11开始,如果a
是int
,则a%256
无法优化为(uint8\t)a
或a&255
。相反,编译器必须生成更像a<0?a |-256:a&255
。我希望有一个标准指定,如果x
和/或y
为负值,并且x
不是y的倍数,x%y
可能产生任意非零值r几乎从来没有用过,而且在旧标准中没有规定,所以为什么需要comp