Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/63.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C如何在内部执行%操作_C_Modulo - Fatal编程技术网

C如何在内部执行%操作

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

我很想了解mod操作背后的逻辑,因为我知道可以执行位移位操作来做不同的事情,比如位移位乘法

我可以看到的一种方法是使用递归算法,该算法一直进行除法,直到无法再除法为止,但这似乎并不有效


任何想法都会有帮助。提前谢谢

虽然大多数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