如何在不使用任何算术运算的情况下找到x mod 15?

时间:2011-07-12 06:38:40

标签: math bit-manipulation

我们给出一个无符号整数,假设。并且不使用任何算术运算符,即+ - / *%,我们将找到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操作基本上是& OxFk基本上是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])

... 等等

这似乎在欺骗我。我希望有一个更优雅的解决方案

2 个答案:

答案 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。