次のビット単位演算子の実際の使用例は何ですか?
- そして
- XOR
- ない
- または
- 左/右シフト
次のビット単位演算子の実際の使用例は何ですか?
回答:
ビットフィールド(フラグ)
それらは、いくつかの "yesまたはno"プロパティによって状態が定義されるものを表す最も効率的な方法です。ACLは良い例です。たとえば、4つの個別のアクセス許可(読み取り、書き込み、実行、ポリシーの変更)がある場合は、無駄にするのではなく、1バイトで保存する方が適切です。これらは、利便性を高めるために、多くの言語で列挙型にマップできます。
ポート/ソケットを介した通信に
は、チェックサム、パリティ、ストップビット、フロー制御アルゴリズムなどが常に含まれます。これは通常、媒体が1ビットしか送信できないため、数値ではなく、個々のバイトの論理値に依存します。時間。
圧縮、暗号化
これらは両方ともビットごとのアルゴリズムに大きく依存しています。例としてdeflateアルゴリズムを見てください。すべてがバイト単位ではなくビット単位です。
有限状態機械
私は主に、ハードウェアの一部に組み込まれている種類について話していますが、ソフトウェアでも見つけることができます。これらは、自然の中で、組み合わせている-彼らはのように表現する必要があるので、彼らは文字通り、論理ゲートの束を「コンパイル」ダウンを取得される可能性がありますAND
、OR
、NOT
、など
グラフィックス
ここには、これらの演算子がグラフィックスプログラミングで使用されるすべての領域に入る十分なスペースがありません。 XOR
(または^
)は、ここで特に興味深いです。同じ入力を2回目に適用すると、最初の入力が取り消されるためです。以前のGUIは、選択の強調表示やその他のオーバーレイをこれに依存して、コストのかかる再描画の必要性を排除していました。これらは、遅いグラフィックプロトコル(リモートデスクトップなど)でも依然として役立ちます。
それらは私が思いついた最初のいくつかの例にすぎません-これは完全なリストではありません。
以下は、個々のビットとして格納されたフラグを扱う一般的な慣用句です。
enum CDRIndicators {
Local = 1 << 0,
External = 1 << 1,
CallerIDMissing = 1 << 2,
Chargeable = 1 << 3
};
unsigned int flags = 0;
課金可能フラグを設定します。
flags |= Chargeable;
CallerIDMissingフラグをクリアします。
flags &= ~CallerIDMissing;
CallerIDMissingおよびChargeableが設定されているかどうかをテストします。
if((flags & (CallerIDMissing | Chargeable )) == (CallerIDMissing | Chargeable)) {
}
CMSのセキュリティモデルの実装にビット演算を使用しました。ユーザーが適切なグループに属している場合、ユーザーがアクセスできるページがありました。ユーザーは複数のグループに属している可能性があるため、ユーザーグループとページグループの間に共通部分があるかどうかを確認する必要がありました。したがって、各グループに一意の2のべき乗の識別子を割り当てました。例:
Group A = 1 --> 00000001
Group B = 2 --> 00000010
Group C = 3 --> 00000100
これらの値のORをとり、その値を(単一のintとして)ページに格納します。たとえば、グループAとBがページにアクセスできる場合、ページアクセスコントロールとして値3(バイナリでは00000011)を格納します。同様に、ユーザーとOR結合されたグループ識別子の値を格納して、どのグループに属しているかを表します。
したがって、特定のユーザーが特定のページにアクセスできるかどうかを確認するには、値をAND演算し、値がゼロ以外かどうかを確認するだけです。このチェックは単一の命令で実装されているため、これは非常に高速で、ループもデータベースのラウンドトリップもありません。
低レベルのプログラミングが良い例です。たとえば、特定のハードウェアに必要な処理を実行させるために、特定のビットをメモリマップドレジスタに書き込む必要がある場合があります。
volatile uint32_t *register = (volatile uint32_t *)0x87000000;
uint32_t value;
uint32_t set_bit = 0x00010000;
uint32_t clear_bit = 0x00001000;
value = *register; // get current value from the register
value = value & ~clear_bit; // clear a bit
value = value | set_bit; // set a bit
*register = value; // write it back to the register
また、htonl()
そしてhtons()
使用して実装されている&
と|
(そのマシン上での演算子をエンディアン(バイトオーダー)ネットワークの順序と一致していません):
#define htons(a) ((((a) & 0xff00) >> 8) | \
(((a) & 0x00ff) << 8))
#define htonl(a) ((((a) & 0xff000000) >> 24) | \
(((a) & 0x00ff0000) >> 8) | \
(((a) & 0x0000ff00) << 8) | \
(((a) & 0x000000ff) << 24))
htons()
およびhtonl()
は、ホスト()のエンディアンからネットワーク()のバイトオーダーにa short
またはa を交換するPOSIX関数です。long
h
n
htonl()
32ビットint
値ではないですか?long
多くの言語で64ビットを意味します。
たとえば、パックされたカラー値からRGB(A)値を取得するために使用します。
(a & b) >> c
は、a % d / e
(ARGBを表すintから単一のカラー値を抽出する両方の方法)よりも5倍以上高速です。それぞれ、10億回の反復で6.7秒と35.2秒。
%
、剰余演算子ではなく剰余演算子であるためです。これらは正の値と同等ですが、負の値とは異なります。適切な制限を提供する場合(たとえばのuint
代わりにint
を渡す)、2つの例は同じ速度になります。
ブールフラグがたくさんあるとき、それらをすべてintに格納するのが好きです。
私はビットごとのANDを使用してそれらを取り出します。例えば:
int flags;
if (flags & 0x10) {
// Turn this feature on.
}
if (flags & 0x08) {
// Turn a second feature on.
}
等
if (flags.feature_one_is_one) { // turn on feature }
。これはANSI C標準に含まれているため、移植性は問題になりません。
&= AND:
特定のビットをマスクします。
表示または非表示にする特定のビットを定義します。0x0&xはバイト内のすべてのビットをクリアし、0xFFはxを変更しません。0x0Fは、下位ニブルのビットを表示します。
変換:
短い変数をビットIDの長い変数にキャストするには、ビットを調整する必要があります。これは、intの-1が0xFFFFFFFFで、longの-1が0xFFFFFFFFFFFFFFFFだからです。IDを保持するには、変換後にマスクを適用します。
| = OR
ビットを設定します。それらが既に設定されている場合、ビットは独立して設定されます。多くのデータ構造(ビットフィールド)には、IS_HSET = 0、IS_VSET = 1のようなフラグがあり、これらを個別に設定できます。フラグを設定するには、IS_HSET |を適用します。IS_VSET(Cおよびアセンブリでは、これは読むのに非常に便利です)
^ = XOR
同じまたは異なるビットを検索します。
〜=
フリップビットではありません。
すべての可能なローカルビット操作がこれらの操作によって実装できることを示すことができます。したがって、必要に応じて、ビット演算のみでADD命令を実装できます。
いくつかの素晴らしいハック:
http://www.ugcs.caltech.edu/~wnoise/base2.html
http://www.jjj.de/bitwizardry/bitwizardrypage.html
= ~
ではない、|=
あるORいます。
& = AND
-なぜ私はすべてのビットをクリアしたいだろう、なぜ私はバイトの無修正バージョンを取得したい、と私は下位ニブルをどうするかだのでしょうか?
xor
それ自体です。私はあなたがより低いニブルを抽出したくなるかもしれないかなりの数の理由を考えることができます。特に、その下位ニブルがデータ構造の一部であり、それをマスクとして、またはOR
別の構造体で使用したい場合。
暗号化はすべてビット単位の操作です。
データをハッシュするための迅速でダーティーな方法としてそれらを使用できます。
int a = 1230123;
int b = 1234555;
int c = 5865683;
int hash = a ^ b ^ c;
これは、ビットマップイメージからバイト形式で色を読み取る例です。
byte imagePixel = 0xCCDDEE; /* Image in RRGGBB format R=Red, G=Green, B=Blue */
//To only have red
byte redColour = imagePixel & 0xFF0000; /*Bitmasking with AND operator */
//Now, we only want red colour
redColour = (redColour >> 24) & 0xFF; /* This now returns a red colour between 0x00 and 0xFF.
この小さな例がお役に立てば幸いです...
今日の現代言語の抽象化された世界では、多すぎません。ファイルIOは簡単に頭に浮かぶものですが、既に実装されているものに対してビット単位の操作を実行しているため、ビット単位の操作を使用するものは実装していません。それでも、簡単な例として、このコードはc#でファイルの読み取り専用属性を削除する(FileMode.Createを指定する新しいFileStreamで使用できるようにする)方法を示しています。
//Hidden files posses some extra attibutes that make the FileStream throw an exception
//even with FileMode.Create (if exists -> overwrite) so delete it and don't worry about it!
if(File.Exists(targetName))
{
FileAttributes attributes = File.GetAttributes(targetName);
if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly)
File.SetAttributes(targetName, attributes & (~FileAttributes.ReadOnly));
File.Delete(targetName);
}
カスタム実装に関する限り、これが最近の例です。私は、分散アプリケーションの1つのインストールから別のインストールに安全なメッセージを送信するための「メッセージセンター」を作成しました。基本的には、メールに似ており、受信トレイ、送信トレイ、送信済みなどが揃っていますが、開封済みメッセージの配信も保証されているため、「受信トレイ」と「送信済み」以外の追加のサブフォルダがあります。これは、「受信トレイ内」や「送信済みフォルダ内」を一般的に定義するための要件でした。送信したフォルダのうち、何を読んだか、何を読んでいないかを知る必要があります。未読のもののうち、何が受信され、何が受信されていないかを知る必要があります。この情報を使用して、ローカルデータソースをフィルタリングし、適切な情報を表示する動的なwhere句を作成します。
列挙型をまとめる方法は次のとおりです。
public enum MemoView :int
{
InboundMemos = 1, // 0000 0001
InboundMemosForMyOrders = 3, // 0000 0011
SentMemosAll = 16, // 0001 0000
SentMemosNotReceived = 48, // 0011
SentMemosReceivedNotRead = 80, // 0101
SentMemosRead = 144, // 1001
Outbox = 272, //0001 0001 0000
OutBoxErrors = 784 //0011 0001 0000
}
これが何をするか分かりますか?「Inbox」列挙値InboundMemosと(&)をアンディングすることで、InboundMemosForMyOrdersが受信トレイにあることがわかります。
次に、現在選択されているフォルダーのビューを定義するフィルターを作成して返すメソッドのボイルダウンバージョンを示します。
private string GetFilterForView(MemoView view, DefaultableBoolean readOnly)
{
string filter = string.Empty;
if((view & MemoView.InboundMemos) == MemoView.InboundMemos)
{
filter = "<inbox filter conditions>";
if((view & MemoView.InboundMemosForMyOrders) == MemoView.InboundMemosForMyOrders)
{
filter += "<my memo filter conditions>";
}
}
else if((view & MemoView.SentMemosAll) == MemoView.SentMemosAll)
{
//all sent items have originating system = to local
filter = "<memos leaving current system>";
if((view & MemoView.Outbox) == MemoView.Outbox)
{
...
}
else
{
//sent sub folders
filter += "<all sent items>";
if((view & MemoView.SentMemosNotReceived) == MemoView.SentMemosNotReceived)
{
if((view & MemoView.SentMemosReceivedNotRead) == MemoView.SentMemosReceivedNotRead)
{
filter += "<not received and not read conditions>";
}
else
filter += "<received and not read conditions>";
}
}
}
return filter;
}
非常に単純ですが、通常はビット単位の演算を必要としない抽象化レベルでのきちんとした実装です。
誰もインターネット時代の明白な答えを選んだとは思わない。サブネットの有効なネットワークアドレスを計算しています。
通常、ビット単位の演算は、乗算/除算を行うよりも高速です。したがって、変数xに9を掛ける必要がある場合は、x<<3 + x
それよりも数サイクル速くなりx*9
ます。このコードがISR内にある場合、応答時間を節約できます。
同様に、配列を循環キューとして使用する場合は、ビット単位の演算でラップアラウンドチェックを処理する方が高速(かつエレガント)です。(配列サイズは2の累乗でなければなりません)。例:、挿入/削除する場合tail = ((tail & MASK) + 1)
はtail = ((tail +1) < size) ? tail+1 : 0
、の代わりに使用できます。
また、エラーフラグに複数のエラーコードを一緒に保持させたい場合は、各ビットに個別の値を保持できます。チェックとして個々のエラーコードとANDすることができます。これはUnixエラーコードで使用されます。
また、nビットのビットマップは、本当にクールでコンパクトなデータ構造になります。サイズnのリソースプールを割り当てる場合は、nビットを使用して現在のステータスを表すことができます。
固定小数点数学については誰も言及していないようです。
(ええ、私は年をとっています、いいですか?)
数x
は2の累乗ですか?(たとえば、カウンターがインクリメントされ、アクションが対数回数だけ実行されるアルゴリズムで有用です)
(x & (x - 1)) == 0
整数の最上位ビットはどれx
ですか?(たとえば、これはより大きい2の最小べき乗を見つけるために使用できますx
)
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x - (x >>> 1); // ">>>" is unsigned right shift
1
整数の最下位ビットはどれx
ですか?(2で割り切れる回数を見つけるのに役立ちます。)
x & -x
x & -x
。最下位のセットビットを見つけるには、を実行します。
ビットワイズ演算子は、長さが2のべき乗である配列のループに役立ちます。多くの人が述べたように、ビットワイズ演算子は非常に便利で、フラグ、グラフィックス、 ネットワーク、暗号化で使用されます。それだけでなく、非常に高速です。私の個人的なお気に入りの使用法は、条件なしで配列をループすることです。あなたが持っていると仮定し、ゼロ・インデックスベースの配列を(例えば最初の要素のインデックスは0である)、あなたはそれ無限にループする必要があります。無期限に、私は最初の要素から最後に行き、最初に戻ることを意味します。これを実装する1つの方法は次のとおりです。
int[] arr = new int[8];
int i = 0;
while (true) {
print(arr[i]);
i = i + 1;
if (i >= arr.length)
i = 0;
}
これは最も単純なアプローチです。if ステートメントを避けたい場合は、次のように係数アプローチを使用できます。
int[] arr = new int[8];
int i = 0;
while (true) {
print(arr[i]);
i = i + 1;
i = i % arr.length;
}
これらの2つの方法の欠点は、整数の除算後に剰余を探すため、モジュラス演算子が高価になることです。そして、最初のメソッドは各反復でifステートメントを実行します。ただし、ビット単位演算子を使用すると、配列の長さが2の累乗の場合、(ビット単位AND)演算子0 .. length - 1
を使用するなどの方法でシーケンスを簡単に生成できます。これを知っていると、上からのコードは&
i & length
int[] arr = new int[8];
int i = 0;
while (true){
print(arr[i]);
i = i + 1;
i = i & (arr.length - 1);
}
これがどのように機能するかです。バイナリフォーマット1減算2の累乗であるすべての数は唯一のもので表されます。たとえば、バイナリの3は11
、7は111
、15は以下の1111
ようになります。ここで、&
バイナリの1のみで構成される数値に対して数値を入力するとどうなりますか?これを行うとしましょう:
num & 7;
場合num
より小さい又は7に等しく、その結果はとなりnum
、各ビットがので&
1と-ed自体です。num
が7より大きい場合、&
操作中、コンピューターは7の先行ゼロを考慮します。もちろん、&
操作後はゼロとして残り、後続部分のみが残ります。9 & 7
バイナリの場合のように、それは次のようになります
1001 & 0111
結果は0001になります。これは10進数で1で、配列の2番目の要素をアドレス指定します。
マイクロコントローラーの出力の一部のビットのみを変更したいが、書き込むレジスタがバイトの場合は、次のようにします(疑似コード)。
char newOut = OutRegister & 0b00011111 //clear 3 msb's
newOut = newOut | 0b10100000 //write '101' to the 3 msb's
OutRegister = newOut //Update Outputs
もちろん、多くのマイクロコントローラでは、各ビットを個別に変更できます...
数値mod(%)の2のべき乗を計算したいyourNumber & 2^N-1
場合は、を使用できますyourNumber % 2^N
。この場合、と同じです。
number % 16 = number & 15;
number % 128 = number & 127;
これはおそらく、2 ^ Nである非常に大きな被除数を持つモジュラス演算の代替手段としてのみ有用ですが、それでも、モジュラス演算に対する速度の向上は、.NET 2.0での私のテストでは無視できます。最近のコンパイラーはすでにこのような最適化を実行していると思います。誰もがこれについてもっと知っていますか?
%
。Remainder操作と同様に、これらは否定を異なる方法で処理します。ただし、に渡すuint
と%
、2番目の引数が既知の2の累乗である場合、C#コンパイラは実際にはビットごとのANDを使用してマシンコードを生成します。
ここで私の質問には現実の使用があります-
最初のWM_KEYDOWN通知のみに応答しますか?
Windows C APIでWM_KEYDOWNメッセージを使用する場合、ビット30は以前のキーの状態を指定します。メッセージが送信される前にキーが押されている場合、値は1です。キーが押されている場合、値は0です。
これらは主にビット単位の演算(サプライズ)に使用されます。PHPコードベースにある実際の例をいくつか示します。
文字コード:
if (s <= 0 && (c & ~MBFL_WCSPLANE_MASK) == MBFL_WCSPLANE_KOI8R) {
データ構造:
ar_flags = other->ar_flags & ~SPL_ARRAY_INT_MASK;
データベースドライバー:
dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READONLY);
コンパイラーの実装:
opline->extended_value = (opline->extended_value & ~ZEND_FETCH_CLASS_MASK) | ZEND_FETCH_CLASS_INTERFACE;
私が最初にCプログラミングを始めたときはいつでも、真理値表などすべてを理解していましたが、この記事を読むまでは、実際にそれを使用する方法を理解できませんでした。http://www.gamedev.net/reference/articles/article1563.asp(実際の例を示します)
x == 1
とy == 2
、その後、x || y
1と評価され、x | y
評価さ0にも、なぜ私は見ていますかx^true
に優れている!x
任意の方法インチ それはタイピングが多く、慣用的でx
はなく、偶然ではない場合はbool
信頼できません。
x^true
より優れているの!x
はsome->complicated().member->lookup ^= true;
、単項演算子の複合代入バージョンがない場合です。
これはビット単位とは見なされませんが、Rubyの配列は通常の整数ビット単位演算子を介して集合演算を定義します。ですから[1,2,4] & [1,2,3] # => [1,2]
。同様のためa ^ b #=> set difference
とa | b #=> union
。