以下链接有点破解,显示如何并行计算模数2 ^ n - 1:ModulusDivisionParallel
你能解释这个位操作是如何工作的,以及如何在给定特定分母的情况下展开显示的循环(参见下面的例子,位掩码来自哪里)?
展开0xF循环的示例:
y = x mod 0xF
y = x & 0x0F0F0F0F + ((x & 0xF0F0F0F0) >> 4)
y = y & 0x00FF00FF + ((y & 0xFF00FF00) >> 8)
y = y & 0x0000FFFF + ((y & 0xFFFF0000) >> 16)
y = y & 0xF
答案 0 :(得分:3)
首先,澄清一下:
当s = 4
(即模数等于0xF
)时,我得到以下展开:
m = (n & 0x0F0F0F0F) + ((n >> 4) & 0x0F0F0F0F)
m = ((n >> 16) + (n & 0x0000FFFF)
m = ((n >> 8) + (n & 0x000000FF)
m = ((n >> 4) + (n & 0x0000000F)
m = ((n >> 4) + (n & 0x0000000F)
m = ((n >> 4) + (n & 0x0000000F)
m = ((n >> 4) + (n & 0x0000000F)
m = m == 0xF ? 0 : m;
这与您在问题中的内容大不相同。解释为什么这有效:
有没有听说过数学技巧,如果你把数字的所有数字加起来并且可以被9整除,那么原来的数字也是?这是有效的,因为将原始和总和除以9的余数是相同的。实际上,这就是我们在这里所做的,只是在不同的基础上 - 在你的例子中,用十六进制基础。
数学功夫是这样的:
每个十六进制数字对最终值的贡献可以表示为V * 16 ^ P
。请注意16 ^ P = 1 (mod 15)
,因此每个十六进制数字对最终值的贡献仅为V (mod 15)
。换句话说,要获得所有数字的总贡献,请将它们全部添加到(mod 15)
。
按位运算只是一种巧妙的方法,以对数步数执行此操作:重复将十六进制数字的前半部分添加到后半部分。
9诀窍的问题是你可能最终得到一个两位数字:99 = 9 + 9 = 18(mod 10)!然后你再次做这个技巧:18 = 1 + 8 = 9(mod 10)。
同样,我们会跟进'额外' m = ((n >> 4) + (n & 0x0000000F)
的迭代,直到剩余的数字是一位数。
现在唯一剩下的细节是,如果我们得到0xF
,那么我们需要0x0
。