モジュラス演算子の代わりにビットごと


89

たとえば、2のべき乗のモジュロは次のように表現できることがわかります。

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

例:

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

2つの数値の一般的な非べき乗についてはどうですか?

まあ言ってみれば:

x%7 ==?


8
@Neil-ModuloとBinaryそしてかなり基本的な操作ですが、どのコンピューター言語でもほぼ同じだと思います。
James Kolpack、2010年

1
私は、彼らが指定されていない場合、私はその手段を想定して、私は通常推測けど言語は:)投稿見ていないのに疲れビットを得るかC ++またはC I不思議ではどのように真の...
Garet Claborn

1
これを理解するのに苦労している人だけのために、stackoverflow.com/ a/ 13784820/1414639を見てください。ああ、JSとV8では、ビット単位の演算子を使用することで、パフォーマンスが非常にわずかに向上します。
Bardi Harbourow、2015年

1
@JamesKolpackビット単位の演算は、モジュロよりもCPUではるかに高速に実行できます。実際、レジスタをゼロにする一般的なアセンブリトリックは、それ自体とXORすることです(このため)。今日、コンパイラーは2の累乗のモジュロを最適化できるかもしれませんが、私にはわかりません
Kaiser Keister

回答:


68

まず第一に、それを言うことは実際には正確ではありません

x % 2 == x & 1

単純な反例:x = -1。Javaを含む多くの言語-1 % 2 == -1。つまり、%必ずしも従来の数学的定義のモジュロではありません。たとえば、Javaでは「剰余演算子」と呼ばれています。

ビット単位の最適化に関しては、2のべき乗のモジュロのみがビット単位の算術演算で「簡単に」実行できます。一般的に言えば、基数bのモジュロベキのみが、数値の基数b表現で「簡単に」実行できます。

たとえば、基数10では、負Nでない値の場合、N mod 10^k最下位k桁のみが使用されます。

参考文献


1
-1 = -1 (mod 2)、あなたが何を手に入れているのかわからない-それはIEEE 754の残りと同じではないということですか?
BlueRaja-ダニープフルフフト

2
@BlueRaja:mod 2の-1の一般的な残差は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 14年

37

ある簡単な方法だけビット単位を使用して2 ^私の番号のモジュロを見つけるために。

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 14

リンクは答えの最良の部分です。
Amit Kumar 2017

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

18

これは2の累乗(多​​くの場合正の1のみ)でのみ機能します。これは、2進数表現で1ビットのみを「1」に設定するという固有のプロパティがあるためです。他のクラスの数値はこのプロパティを共有しないため、ほとんどのモジュラス式に対してビットごとのAND式を作成することはできません。


1
もしあなたがたまたま三元アーキテクチャで動作しているなら、それは物事を少し変えます...しかし、チャンスはほとんどゼロです。
Noldorin 2010年

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
スリラムムラリ

10
また、モジュロの使用を避けたいのに、なぜ分割したいのですか?私の知る限り、割り算の命令は残りを得る命令と同じです。
ホーススミス

1
@SriramMuraliつまり、偶数のmodを使用したので、もちろん機能しません。これは、OPが言ったように、奇数の回避策です。
ylun.ca 2015

3

ビットごとのand(&バイナリで)演算子ない場合はありません。証明のスケッチ:

次のような値kがあったとしますx & k == x % (k + 1)が、k!= 2 ^ n-1です。次に、x == kの場合、式x & kは「正しく動作する」ように見え、結果はkになります。ここで、x == kiについて考えます。kに「0」ビットがあった場合、0より大きいiがいくつかあります。これらの位置では、kiは1ビットでしか表現できません。(たとえば、10 11(11)は、100(4)が減算されると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を使用すると、ビット構成を別のビット構成に変更できます(つまり、これらの演算子のセットは「機能的に完全」です)。ただし、モジュラスなどの操作の場合、一般式は必然的にかなり複雑になるため、それを再作成しようとすることさえありません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.