我们给出一个无符号整数,假设。并且不使用任何算术运算符,即+
-
/
*
或%
,我们将找到x mod 15
。我们可能会使用二进制位操作。
据我所知,我基于2分得到了这个。
a = a mod 15 = a mod 16
的 a<15
让a = x mod 15
然后a = x - 15k
(对于某些非负k
)。
即a = x - 16k + k
...
即a mod 16 = ( x mod 16 + k mod 16 ) mod 16
即a mod 15 = ( x mod 16 + k mod 16 ) mod 16
即a = ( x mod 16 + k mod 16 ) mod 16
行。现在来实现这一点。 mod16
操作基本上是& OxF
。 k
基本上是x>>4
所以a = ( x & OxF + (x>>4) & OxF ) & OxF
。
归结为添加2个4位数字。这可以通过位表达式完成。
sum[0] = a[0] ^ b[0]
sum[1] = a[1] ^ b[1] ^ (a[0] & b[0])
... 等等
这似乎在欺骗我。我希望有一个更优雅的解决方案
答案 0 :(得分:9)
这让我想起了10号基地的一个名为“赶走9”的老把戏。这用于检查手工执行的大笔金额的结果。
在这种情况下123 mod 9 = 1 + 2 + 3 mod 9 = 6
。
这是因为9比数字(10)的基数小1。 (证明省略;))
因此考虑基数16(十六进制)中的数字。你应该能够做到:
0xABCE123 mod 0xF = (0xA + 0xB + 0xC + 0xD + 0xE + 0x1 + 0x2 + 0x3 ) mod 0xF
= 0x42 mod 0xF
= 0x6
现在你仍然需要做一些魔术才能使添加消失。但它给出了正确的答案。
更新:
这是一个完整的C ++实现。 f
查找表将成对的数字与它们的和模15进行比较(这与字节模15相同)。然后,我们重新打包这些结果,每轮重新应用一半的数据。
#include <iostream>
uint8_t f[256]={
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,0,
1,2,3,4,5,6,7,8,9,10,11,12,13,14,0,1,
2,3,4,5,6,7,8,9,10,11,12,13,14,0,1,2,
3,4,5,6,7,8,9,10,11,12,13,14,0,1,2,3,
4,5,6,7,8,9,10,11,12,13,14,0,1,2,3,4,
5,6,7,8,9,10,11,12,13,14,0,1,2,3,4,5,
6,7,8,9,10,11,12,13,14,0,1,2,3,4,5,6,
7,8,9,10,11,12,13,14,0,1,2,3,4,5,6,7,
8,9,10,11,12,13,14,0,1,2,3,4,5,6,7,8,
9,10,11,12,13,14,0,1,2,3,4,5,6,7,8,9,
10,11,12,13,14,0,1,2,3,4,5,6,7,8,9,10,
11,12,13,14,0,1,2,3,4,5,6,7,8,9,10,11,
12,13,14,0,1,2,3,4,5,6,7,8,9,10,11,12,
13,14,0,1,2,3,4,5,6,7,8,9,10,11,12,13,
14,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,
0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,0};
uint64_t mod15( uint64_t in_v )
{
uint8_t * in = (uint8_t*)&in_v;
// 12 34 56 78 12 34 56 78 => aa bb cc dd
in[0] = f[in[0]] | (f[in[1]]<<4);
in[1] = f[in[2]] | (f[in[3]]<<4);
in[2] = f[in[4]] | (f[in[5]]<<4);
in[3] = f[in[6]] | (f[in[7]]<<4);
// aa bb cc dd => AA BB
in[0] = f[in[0]] | (f[in[1]]<<4);
in[1] = f[in[2]] | (f[in[3]]<<4);
// AA BB => DD
in[0] = f[in[0]] | (f[in[1]]<<4);
// DD => D
return f[in[0]];
}
int main()
{
uint64_t x = 12313231;
std::cout<< mod15(x)<<" "<< (x%15)<<std::endl;
}
答案 1 :(得分:2)
你的逻辑存在缺陷,但我不能指责它。你自己考虑一下,你的最终公式是在前8位运行而忽略其余的。只有当你丢弃的部分(9+位)总是 15的乘法时,这才有效。但是,实际上(二进制数)9+位总是乘以16但不是15例如,尝试将1 0000 0000和11 0000 0000放入公式中。对于这两种情况,你的公式将给出0,而实际上答案是1和3。
在本质上,我几乎可以肯定,如果没有循环,你的任务就无法解决。如果你被允许使用循环 - 那么实现bitwiseAdd函数并用它做任何你想做的事情都没有比这更容易了。
<强>加了:强>
找到你的问题。这是:
... a = x - 15k(对于某些非负k)。
...并且k基本上是x>&gt;&gt; 4
只有一些数字的纯巧合等于x>&gt; 4。举个例子,比如x = 11110000。通过你的计算k = 15,而实际上它是k = 16:16 * 15 = 11110000。