按位并代替模数运算符

时间:2010-06-18 19:55:28

标签: algorithm

我们知道,例如两个幂的模数可以这样表达:

  x % 2 inpower n == x & (2 inpower n - 1).

示例:

x % 2 == x & 1
x % 4 == x & 3
x % 8 == x & 7 

两个数字的一​​般非权力怎么样?

让我们说:

x%7 ==?

10 个答案:

答案 0 :(得分:61)

首先,说实际上并不准确

x % 2 == x & 1

简单的反例:x = -1。在许多语言中,包括Java,-1 % 2 == -1。也就是说,%不一定是模数的传统数学定义。例如,Java将其称为“余数运算符”。

关于按位优化,只有2的模幂可以在按位算术中“轻松”完成。一般来说,只有基数 b 的模幂才能“轻松”用基数 b 表示数字。

在基数10中,例如,对于非负NN mod 10^k只是取最不重要的k数字。

参考

答案 1 :(得分:30)

只有一种简单的方法可以使用按位找到2 ^ i个数字的模数。

有一种巧妙的方法来解决Mersenne个案例as per the link,例如n%3,n%7 ...... n%5,n%255和复合案例(例如n%6)有特殊情况。

对于案例2 ^ i,(2,4,8,16 ......)

n % 2^i = n & (2^i - 1)

更复杂的事情很难解释。只有在你非常好奇的时候才能阅读。

答案 2 :(得分:17)

这仅适用于2的幂(并且通常只有正数),因为它们具有在其二进制表示中仅将一个位设置为“1”的唯一属性。因为没有其他类的数字共享此属性,所以不能为大多数模数表达式创建按位和表达式。

答案 3 :(得分:9)

这是一个特殊情况,因为计算机代表基数2中的数字。这是可推广的:

(数字) base %base x

与(number) base 的最后x位数相等。

答案 4 :(得分:5)

除了2的幂之外,还存在有效算法的模数。

例如,如果x是32位unsigned int那么 x%3 = popcnt(x& 0x55555555) - popcnt(x& 0xaaaaaaaa)

答案 5 :(得分:4)

没有“%”运算符的模数“7”

int a = x % 7;

int a = (x + x / 7) & 7;

答案 6 :(得分:3)

不使用二进制中的按位和(&)运算符,没有。证明草图:

假设有一个值 k x & k == x % (k + 1),但 k!= 2 ^ n - 1 。然后,如果 x == k ,表达式x & k似乎“正常运行”,结果是 k 。现在,考虑 x == ki :如果 k 中有任何“0”位,则有一些 i 大于0 > ki 只能在这些位置用1位表示。 (例如,当从中减去100(4)时,1011(11)必须变为0111(7),在这种情况下,当 i = 4 时,000位变为100。)如果来自 k 的表达式必须从0变为1才能表示 ki ,然后才能正确计算 x%(k + 1),其中case应该是 ki ,但是没有办法按位布尔并且在给定掩码的情况下产生该值。

答案 7 :(得分:2)

在这个特定情况下(mod 7),我们仍然可以用位运算符替换%7:

// Return X%7 for X >= 0.
int mod7(int x)
{
  while (x > 7) x = (x&7) + (x>>3);
  return (x == 7)?0:x;
}

它起作用,因为8%7 = 1.显然,这个代码可能效率低于简单的x%7,而且可读性差。

答案 8 :(得分:1)

使用bitwise_and,bitwise_or和bitwise_not可以将任何位配置修改为另一个位配置(即这些运算符集“功能完整”)。但是,对于像模数这样的操作,通用公式必然会非常复杂,我甚至不愿意尝试重新创建它。

答案 9 :(得分:-1)

只有一种简单的方法可以使用按位来查找2 ^ i数的模数。

根据n%3,n%7这样的链接有一种巧妙的方法可以解决Mersenne案例... n%5,n%255和n%6等复合案例都有特殊情况。

对于案例2 ^ i,(2,4,8,16 ......)

n%2 ^ i = n& (2 ^ i - 1)

更复杂的事情很难解释。只有在你非常好奇的时候才能阅读。

@ Murali n%[(2 ^ 16)+1] = 65537的任何此类方法。我的意思是n%(2 ^ k)+1,这是一个素数。