web-dev-qa-db-ja.com

開発者が知っておくべき有益なビット演算子コードのトリックは何ですか?

私はビット単位演算子を使用する理由がなかったと言わなければなりませんが、私はそれらでより効率的に行われたであろう私が実行したいくつかの操作があると確信しています。 「シフト」と「OR-ing」は、問題をより効率的に解決するのにどのように役立ちましたか?

62
non sequitor

有名な Bit Twiddling Hacks を参照してください
乗算/除算のほとんどは不要です-コンパイラが自動的にそれを行い、ユーザーを混乱させるだけです。

ただし、ハードウェアまたは通信プロトコルを使用する場合に非常に役立つ「チェック/セット/トグルビットN」タイプのハックが多数あります。

42
Martin Beckett

文字列(文字)でビット演算を使用する

文字を小文字に変換します:

  • OR by space => _(x | ' ')_
  • 文字がすでに小文字であっても、結果は常に小文字です
  • 例えば。 _('a' | ' ') => 'a'_; _('A' | ' ') => 'a'_

文字を大文字に変換します:

  • AND下線で=> _(x & '_')_
  • 文字がすでに大文字であっても、結果は常に大文字です
  • 例えば。 _('a' & '_') => 'A'_; _('A' & '_') => 'A'_

反転手紙の場合:

  • XORスペースで== _(x ^ ' ')_
  • 例えば。 _('a' ^ ' ') => 'A'_; _('A' ^ ' ') => 'a'_

アルファベットの位置

  • AND by chr(31)/binary('11111') /(hex('1F') => _(x & "\x1F")_
  • 結果は1..26の範囲で、大文字と小文字は重要ではありません
  • 例えば。 _('a' & "\x1F") => 1_; _('B' & "\x1F") => 2_

文字の位置をアルファベットで取得します(大文字文字のみ):

  • AND by _?_ => _(x & '?')_orXOR by _@_ => _(x ^ '@')_
  • 例えば。 _('C' & '?') => 3_; _('Z' ^ '@') => 26_

文字のpositionをアルファベットで取得(小文字文字のみ):

  • XOR backtick/chr(96)/binary('1100000')/hex('60') => _(x ^ '`')_
  • 例えば。 _('d' ^ '`') => 4_; _('x' ^ '`') => 25_

注:英語以外の文字を使用すると、ガベージ結果が生成されます

134
CSᵠ

  • 整数のビット演算(int)

最大整数を取得

int maxInt = ~(1 << 31);
int maxInt = (1 << 31) - 1;
int maxInt = (1 << -1) - 1;

最小整数を取得

int minInt = 1 << 31;
int minInt = 1 << -1;

最大長を取得

long maxLong = ((long)1 << 127) - 1;

2で乗算

n << 1; // n*2

2で割る

n >> 1; // n/2

2のm乗で乗算

n << m;

2のm乗で除算

n >> m;

奇数を確認

(n & 1) == 1;

2つの値を交換

a ^= b;
b ^= a;
a ^= b;

絶対値を取得

(n ^ (n >> 31)) - (n >> 31);

2つの値の最大値を取得

b & ((a-b) >> 31) | a & (~(a-b) >> 31);

2つの値の最小値を取得

a & ((a-b) >> 31) | b & (~(a-b) >> 31);

両方に同じ符号があるかどうかを確認

(x ^ y) >= 0;

2 ^ nを計算

2 << (n-1);

2の階乗であるかどうか

n > 0 ? (n & (n - 1)) == 0 : false;

mに対するモジュロ2 ^ n

m & (n - 1);

平均を取得

(x + y) >> 1;
((x ^ y) >> 1) + (x & y);

nのm番目のビットを取得する(低から高へ)

(n >> (m-1)) & 1;

nのm番目のビットを0(低から高)に設定

n & ~(1 << (m-1));

n + 1

-~n

n-1

~-n

コントラスト番号を取得

~n + 1;
(n ^ -1) + 1; 

if(x == a)x = b; if(x == b)x = a;

x = a ^ b ^ x;
57
Mohasin Ali

どの周波数でもこれまでに使用したことがあるのは3つだけです。

  1. ビットを設定します。a| = 1 <<ビット。

  2. ビットをクリアします:&=〜(1 <<ビット);

  3. ビットが設定されていることをテストします:&(1 <<ビット);

13
Scott

Matters Computational:Ideas、Algorithms、Source Code、by Jorg Arndt(PDF) 。この本にはたくさんのものが含まれています。 http://www.hackersdelight.org/ のリンクから見つけました。

オーバーフローなしの平均

2つの引数xとyの平均(x + y)/ 2を計算するルーチンは次のとおりです。

static inline ulong average(ulong x, ulong y)
// Return floor( (x+y)/2 )
// Use: x+y == ((x&y)<<1) + (x^y)
// that is: sum == carries + sum_without_carries
{
    return (x & y) + ((x ^ y) >> 1);
}
6
u0b34a0f6ae

データを圧縮できます。整数のコレクション:

  • コレクションでより頻繁に現れる整数値を確認します
  • より頻繁に現れる値を表すために短いビットシーケンスを使用する (より頻繁に現れる値を表すために長いビットシーケンスを使用する)
  • ビットシーケンスを連結します。たとえば、結果のビットストリームの最初の3ビットは1つの整数を表し、次の9ビットは別の整数を表します。
3
ChrisW

ビット文字列 の距離計算を効率的に実装するためにビット演算子を使用しました。私のアプリケーションでは、ビット列を使用して、離散化されたスペース( octree の位置を表します。興味がある場合は、 モートン順序付け )。距離計算は、グリッド上のポイントが特定の半径内に収まったかどうかを知るために必要でした。

2
ire_and_curses

セットビットのカウント、最低/最高セットビットの発見、上から/下のセットビットの発見、その他は有用であり、 bit-twiddling hacks サイトを見る価値があります。

そうは言っても、この種のことは日常的には重要ではありません。ライブラリがあると便利ですが、それでも最も一般的な用途は間接的です(ビットセットコンテナを使用するなど)。また、理想的には、これらは標準のライブラリ関数になります-それらの多くは、一部のプラットフォームで特殊なCPU命令を使用してより適切に処理されます。

2
Steve314

1)2の累乗で除算/乗算する

foo >>= x;(2の累乗で除算)

foo <<= x;(2のべき乗)

2)スワップ

x ^= y;
y = x ^ y;
x ^= y;
2
Taylor Leese

シフトによる乗算/除算は気の利いたようですが、たまに必要なのはブール値をビットに圧縮することだけでした。そのためには、ビット単位のAND/ORと、おそらくビットシフト/反転が必要です。

1
sbi

数値を次に高い2のべき乗に丸める関数が必要だったので、数回呼び出されたBit TwiddlingのWebサイトにアクセスして、次のように考えました。

_i--;
i |= i >> 1;
i |= i >> 2;
i |= i >> 4;
i |= i >> 8;
i |= i >> 16;
i++;
_

_size_t_型で使用します。おそらく署名されたタイプではうまく動作しません。サイズの異なるタイプのプラットフォームへの移植性が心配な場合は、適切な場所に#if SIZE_MAX >= (number)ディレクティブをコードに振りかけます。

1
Chris Lutz