按位代替模运算符


90

我们知道例如2的幂的模可以这样表示:

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

例子:

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

一般两个数的无幂呢?

比方说:

x%7 ==?


8
@Neil-Modulo和Binary而且都是非常基本的操作,我猜它们在任何计算机语言中都差不多。
James Kolpack 2010年

1
我得到一个有点累没有看到语言张贴:)虽然我通常都是猜的,如果他们不指定,我假设手段C ++或C我不知道这是多么真实..
杰拉尔德Claborn

1
只是对于那些努力理解这一点的人来说,请看一下stackoverflow.com/a/13784820/1414639。哦,在带有V8的JS中,我通过使用按位运算符获得了非常轻微的性能提升。
Bardi Harborow'Mar

1
@JamesKolpack在CPU上执行按位运算的速度比对模运算的速度快得多。实际上,将寄存器清零的常见汇编技巧是对其进行异或操作(因为这个事实)。如今,编译器也许可以优化2的幂的模,但我不知道
Kaiser Keister

Answers:


70

首先,说这实际上是不准确的

x % 2 == x & 1

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

关于按位优化,在按位算术中只能“轻松”完成两个模的幂。一般来说,基地只有模权力b可以“轻易”地与基地做b数字表示。

例如,对于非负数N,以10为底N mod 10^k仅取最低有效k数字。

参考文献


1
-1 = -1 (mod 2),不知道你在说什么-你的意思是不一样的IEEE 754余?
BlueRaja-Danny Pflughoeft

2
@BlueRaja:为-1模2的共同的残基是1个en.wikipedia.org/wiki/Modular_arithmetic#Remainders
polygenelubricants

@BlueRaja:如果允许负数,则基本上可以确定(特别是因为未提及任何语言)(a / b) / b + a % b == a,对于C型运算符,a和b整数,b非零以及abs(a % b) < abs(b)具有相同的条件。
David Thornley 2010年

1
@DavidThornley-假设您的意思是(a / b)* b + a % b == a
sfjac

40

目前只有一个简单的方法来找到使用逐2 ^我数模。

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

对于情况2 ^ i,(2,4,8,16 ...)

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

更复杂的很难解释。仅当您非常好奇时才阅读。


1
投票++; 优秀的链接,谢谢参考。我建议其他人看看,即使有些复杂,也值得阅读。
varzeak 2014年

链接是答案的最好部分。
阿米特·库玛

n%2 ^ i = n&(1 << i-1)
Kartik Singh

18

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


2
如果您恰巧是在三元体系结构上运行,那么情况会有所改变...但是机会大约为零。
Noldorin 2010年

我喜欢您的措辞:“那会稍微改变事情”
j3141592653589793238

12

这是一种特殊情况,因为计算机以2为底数。这是可概括的:

(数量)基础%基础x

等价于(number)base的最后x位数字。


5

除了2的幂以外,还有其他模数,这些模数存在有效的算法。

例如,如果x是32位无符号整数,则x%3 = popcnt(x&0x55555555)-popcnt(x&0xaaaaaaaa)


4

模数“ 7”,无“%”运算符

int a = x % 7;

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

3
对于10%2 = 0无效。(10 + 10/2)&2 = 15&2 = 2,类似地10%6 = 4((10 + 10/6)&6 = 11&6 = 2
Sriram Murali13年

10
另外,为什么要避免使用模数时要除法?AFAIK,除法指令与获得余数的法则相同。
马SMith

1
@SriramMurali那是因为您使用了偶数mod,当然它是行不通的,这是OP所说的解决奇怪问题的方法。
ylun.ca 2015年

3

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

假设有一个这样的值kx & 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表达式中的某个位必须从零变为一个代表,则它无法正确计算x%(k + 1),在这种情况下应为ki,但无法实现按位布尔值,也无法在给定掩码的情况下生成该值。


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效率低,而且可读性也较低。


1

使用bitwise_and,bitwise_or和bitwise_not,您可以将任何位配置修改为另一位配置(即,这些运算符集“在功能上是完整的”)。但是,对于模数之类的运算,通用公式必然会非常复杂,我什至不必费心尝试重新创建它。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.