次のビット演算子の実際の使用例は何ですか?
ビットフィールド(フラグ)
これらは、複数の「yesまたはno」プロパティによって状態が定義されているものを表す最も効率的な方法です。 ACLは良い例です。 4つの個別のアクセス許可(読み取り、書き込み、実行、ポリシーの変更)がある場合、4を無駄にするのではなく1バイトに保存することをお勧めします。これらは、利便性を高めるために多くの言語の列挙型にマップできます。
ポート/ソケットを介した通信
常にチェックサム、パリティ、ストップビット、フロー制御アルゴリズムなどが含まれます。これらは通常、数値ではなく個々のバイトの論理値に依存します。時間。
圧縮、暗号化
これらの両方は、ビット単位のアルゴリズムに大きく依存しています。例として deflate アルゴリズムを見てください-すべてはバイトではなくビットです。
有限状態マシン
私は主にいくつかのハードウェアに埋め込まれている種類のことを言っていますが、それらはソフトウェアにもあります。これらは本質的に組み合わせです。文字通り「コンパイル」されて論理ゲートの束になることがあるため、AND
、OR
、NOT
などとして表現する必要があります。
グラフィックスこれらの演算子がグラフィックスプログラミングで使用されるすべての領域に入るための十分なスペースはありません。 XOR
(または^
)は、同じ入力を2回適用すると最初の入力が元に戻されるため、特に興味深いものです。コストのかかる再描画の必要性を排除するために、選択の強調表示やその他のオーバーレイをこれに依存していた古いGUI。低速のグラフィックプロトコル(リモートデスクトップなど)でも引き続き有用です。
これらは、私が思いついた最初の数例に過ぎません-これは完全なリストではありません。
奇妙ですか?
(value & 0x1) > 0
2(偶数)で割り切れますか?
(value & 0x1) == 0
低レベルのプログラミングが良い例です。たとえば、メモリマップドレジスタに特定のビットを書き込んで、ハードウェアの一部に必要な処理を実行させる必要がある場合があります。
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))
個別のビットとして保存されたフラグを扱う一般的なイディオムを次に示します。
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して、値がゼロ以外であるかどうかを確認するだけです。このチェックは単一の命令で実行され、ループもデータベースの往復も行われないため、これは非常に高速です。
たとえば、それらを使用して、パックされたカラー値からRGB(A)値を取得します。
多数のブールフラグがある場合、それらをすべてintに格納するのが好きです。
ビット単位のANDを使用してそれらを取り出します。例えば:
int flags;
if (flags & 0x10) {
// Turn this feature on.
}
if (flags & 0x08) {
// Turn a second feature on.
}
等.
&= AND:
特定のビットをマスクします。
表示または非表示する特定のビットを定義しています。 0x0&xはバイト内のすべてのビットをクリアし、0xFFはxを変更しません。 0x0Fは、下位ニブルのビットを表示します。
変換:
。アイデンティティを保持するには、変換後にマスクを適用します。
| = OR
ビットを設定します。既に設定されている場合、ビットは独立して設定されます。多くのデータ構造(ビットフィールド)には、IS_HSET = 0、IS_VSET = 1などのフラグがあり、これらは個別に設定できます。フラグを設定するには、IS_HSET | Apply IS_VSET(Cおよびアセンブリでは、これは非常に便利です)
^ = XOR
同じまたは異なるビットを検索します。
〜= NOT
ビットを反転します。
all可能なローカルビット操作は、これらの操作によって実装できることが示されます。必要に応じて、ビット演算のみでADD命令を実装できます。
素晴らしいハック:
http://www.ugcs.caltech.edu/~wnoise/base2.html
http://www.jjj.de/bitwizardry/bitwizardrypage.html
暗号化はすべてビット単位の操作です。
データをハッシュするための迅速で汚い方法として使用できます。
int a = 1230123;
int b = 1234555;
int c = 5865683;
int hash = a ^ b ^ c;
PLCとのシリアル通信のチェックサムを計算するために、約3分前にビット単位のXOR(^
)を使用しました...
これは、バイト形式のビットマップ画像から色を読み取る例です
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.
この小さな例がお役に立てば幸いです...
ビット単位の&は、バイトの特定の部分をマスク/抽出するために使用されます。
1バイト変数
01110010
&00001111 Bitmask of 0x0F to find out the lower nibble
--------
00000010
特に、シフト演算子(<< >>)が計算によく使用されます。
今日の現代言語の抽象化された世界では、多すぎません。 File 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);
}
カスタム実装に関しては、最近の例です:分散アプリケーションのインストールから別のインストールに安全なメッセージを送信するための「メッセージセンター」を作成しました。基本的に、受信トレイ、送信トレイ、送信済みなどを備えた電子メールに似ていますが、開封確認付きの配信も保証されているため、「受信トレイ」と「送信済み」以外のサブフォルダーがあります。これは、「受信トレイにあるもの」または「送信済みフォルダーにあるもの」を一般的に定義するための要件でした。送信されたフォルダのうち、何が読まれ、何が未読かを知る必要があります。未読のもののうち、受け取ったものと受け取っていないものを知る必要があります。この情報を使用して、ローカルデータソースをフィルタリングし、適切な情報を表示する動的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とのAND(&)により、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;
}
非常に単純ですが、抽象レベルでのきちんとした実装であり、通常はビット単位の操作を必要としません。
Base64エンコーディングは一例です。 Base64エンコーディングは、電子メールシステム(およびその他の目的)で送信するための印刷可能な文字としてバイナリデータを表すために使用されます。 Base64エンコードは、一連の8ビットバイトを6ビット文字ルックアップインデックスに変換します。 Base64エンコードおよびデコードに必要なビット演算を実装するには、ビット演算、シフト、および「ing」または「ing」、「not」の表記が非常に便利です。
もちろん、これは数え切れないほどの例の1つにすぎません。
インターネット時代の明らかな答えを誰も選ばなかったのには驚いた。サブネットの有効なネットワークアドレスの計算。
固定小数点演算について言及した人はいないようです。
(ええ、私は古いです、大丈夫ですか?)
通常、ビット単位の演算は、乗算/除算を行うよりも高速です。したがって、変数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ビットを使用して現在のステータスを表すことができます。
私はそれらを複数選択オプションに使用し、このように10以上ではなく1つの値のみを保存します
sQLリレーショナルモデルでも便利です。次のテーブルがあるとします。BlogEntry、BlogCategory
従来、BlogEntryCategoryテーブルを使用してそれらの間にnn関係を作成するか、BlogEntryで1つの値を使用して、フラグ付き列挙と同様に複数のBlogCategoryレコードにリンクできるBlogCategoryレコードがほとんどない場合、ほとんどのRDBMSその「フラグ付き」列で選択する非常に高速な演算子...
マイクロコントローラの出力の一部のビットのみを変更したいが、書き込むレジスタがバイトである場合、次のようなことを行います(擬似コード):
char newOut = OutRegister & 0b00011111 //clear 3 msb's
newOut = newOut | 0b10100000 //write '101' to the 3 msb's
OutRegister = newOut //Update Outputs
もちろん、多くのマイクロコントローラーでは、各ビットを個別に変更できます...
数値x
は2の累乗ですか? (たとえば、カウンターがインクリメントされ、アクションが対数回数だけ行われるアルゴリズムで有用です)
(x & (x - 1)) == 0
整数x
の最上位ビットはどれですか? (たとえば、これはx
よりも大きい最小の2のべき乗を見つけるために使用できます)
x |= (x >> 1);
x |= (x >> 2);
x |= (x >> 4);
x |= (x >> 8);
x |= (x >> 16);
return x - (x >>> 1); // ">>>" is unsigned right shift
整数x
の最下位1
ビットはどれですか? (2で割り切れる回数を見つけるのに役立ちます。)
x & -x
数値mod(%)を特定の2の累乗で計算したい場合は、yourNumber & 2^N-1
を使用できます。この場合、yourNumber % 2^N
と同じです。
number % 16 = number & 15;
number % 128 = number & 127;
これはおそらく、2 ^ Nの非常に大きな配当を伴うモジュラス演算の代替としてのみ有用です...しかし、それでもモジュラス演算の速度向上は、.NET 2.0での私のテストでは無視できます。現代のコンパイラはすでにこのような最適化を実行していると思われます。誰もこれについてもっと知っていますか?
ハノイの塔線形ソリューションは、ビット演算を使用して問題を解決します。
public static void linear(char start, char temp, char end, int discs)
{
int from,to;
for (int i = 1; i < (1 << discs); i++) {
from = (i & i-1) % 3;
to = ((i | i-1) + 1) % 3;
System.out.println(from+" => "+to);
}
}
このソリューションの説明は here にあります。
それらは主にビット単位の操作に使用されます(驚き)。 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;
これはビット単位とは見なされませんが、Rubyの配列は通常の整数ビット単位演算子を使用して集合演算を定義します。だから[1,2,4] & [1,2,3] # => [1,2]
。 a ^ b #=> set difference
およびa | b #=> union
についても同様です。
ロールベースのアクセス制御システムで使用されているのを見てきました。
最初にCプログラミングを始めたときはいつでも、真理値表とそのすべてを理解していましたが、この記事を読むまで実際に使用する方法についてはクリックしませんでした http://www.gamedev.net/reference/articles /article1563.asp (実際の例を示します)
ここで私の質問に実際の使用があります-
最初のWM_KEYDOWN通知のみに応答しますか?
Windows C APIビット30でWM_KEYDOWNメッセージを使用する場合、以前のキー状態を指定します。値は、メッセージが送信される前にキーがダウンしている場合は1、キーがアップしている場合はゼロです。
数回のゲーム開発の本で、乗算と除算のより効率的な方法としてそれを見てきました。
2 << 3 == 2 * 8
32 >> 4 == 32 / 16
まだ誰もコレクションに言及していません。場合によっては、可能な値の小さなコレクション、たとえば10または20の可能な値のみがあり、それらの一部をセットに保持したい場合があります。確かに通常のSet
実装を使用できますが、これはおそらくバッキングハッシュテーブルを使用します。しかし、可能な値のセットは非常に小さいため、これは実際には時間とスペースの無駄にすぎません。代わりに、正しく覚えていれば、Java int
が行うこととまったく同じ単一のlong
またはEnumSet
値にセットを格納できます。
高速BCD計算を実装するためにそれらを使用します(会計士と監査人はfp丸めに腹を立てます)。
私は常にビット単位の操作は実行するのが非常に簡単な操作であると仮定していました。したがって、実行時間が重要な場合、ビットセットを介して実装されるソリューションは、アルゴリズムに応じて一定量だけ実行時間を改善できます。
Bitwise Flagsを使用して、内部Webサイトでのログイン許可のセッションを小さくします。
一般的な用途はアライメントです。たとえば、データを4バイトまたは16バイトの境界にアライメントする必要があります。これは、アライメントされていないロード/ストアが高価なRISCプロセッサで非常に一般的です位置合わせされていない負荷まで)またはまったく許可されません。
2の累乗であるアライメントの場合、次のアライメントされたposは次のように計算できます。
aligned_offset = alignment + ((current_offset - 1) & ~(alignment - 1))
したがって、4バイトの位置合わせと9の現在のオフセットの場合:
aligned_offset = 4 + ((9-1) & ~(4-1)) = 4 + (8 & 0xFFFFFFFC) = 4+ 8 = 12
したがって、次の4バイトにアライメントされたオフセットは12になります。
オプションの組み合わせを単一の整数に格納するために、ビット演算をよく使用します。
int options = 0;
OPTION1
は1、OPTION2
は2、OPTION3
は4、OPTION4
は8、OPTION5
は16、...
void addOption(int option)
は、|
演算子を使用してオプションをオプションに追加します。
boolean hasOption(int option)
は、&
演算子を使用して、オプション内のオプションをテストします。
それらをオプションハンドラとして使用します。アクセス制御リストで特定のリソースを説明します。
この記事をご覧ください http://planetozh.com/blog/2006/05/php-bitwise-operators-example-of-use/
もう1つのリンク: http://blog.code-head.com/how-to-write-a-permission-system-using-bits-and-bitwise-operations-in-php
しばらく前に binary writer/reader を示す小さなwiki記事を書きました。ビットレベルで動作し、ビット演算子を使用してデータをパックする方法を示します。それはおそらくゲームでの用途があるので、「現実世界」の例でしょう。
非常に具体的な例ですが、数独ソルバーをより速く実行するためにそれらを使用しました(友人と競争していました)
各列、行、および3x3は符号なし整数として表され、数値を設定すると、関連列、行、および3x3の正方形に設定された数値の適切なビットにフラグを立てます。
これにより、右の列、行、3x3の正方形をORするので、与えられた正方形に配置できる数字を簡単に確認できます。特定のポジションの有効な値。
それが理にかなっていることを願っています。
データベースの世界におけるもう1つの現実のアプリケーションは、MySQLであり、これは SET と呼ばれるデータ型を持っています。
ビット単位演算子は、DBMSによってSETデータ型を格納します。セットはスペースを節約できます。
Element SET Value Decimal Value
Travel 00000001 1
Sports 00000010 2
Dancing 00000100 4
Fine Dining 00001000 8