最近、私はgolang仕様を読み、いくつかの興味深い演算子に直面しました:
& bitwise AND integers
| bitwise OR integers
^ bitwise XOR integers
&^ bit clear (AND NOT) integers
私はそれで遊んでみましたが、私が理解した唯一のものは、その「|」です整数を追加し、「+」演算子はフロート、文字列などでさらに機能します。
実際に使用されるのは何ですか?上記の4人のオペレーターについて誰か説明していただけますか?
byte-またはbit-level dataで作業する必要がある場合、ビット単位演算子が作用します。
ここに、コードサンプルでビット演算を使用したいくつかの例をリストします(順不同)。
1.これらは共通であり、暗号化およびハッシュ関数の多くのアルゴリズムの一部です(例 MD5 )。
2.スペースを「節約」したい場合にもよく使用されます複数の「ブール」変数をパックを1つのint
にまとめますたとえば、各bool変数にビットを割り当てます。ビットを個別に変更/読み取りできるようにするには、ビットごとの演算子を使用する必要があります。
たとえば、8ビット/ブールを1つのint
にパックする場合:
flags := 0x00 // All flags are 0
flags |= 0x02 // Turn the 2nd bit to 1 (leaving rest unchanged)
flags |= 0xff // Turn 8 bits (0..7) to 1
flags &= 0xfe // Set the lowest bit to 0 (leaving rest unchanged)
istrue := flags&0x04 != 0 // Test if 3rd bit is 1
3.別の領域はデータの圧縮で、byte
を最大限に活用し、そのすべてのビットを使用して格納/取得します。一部の情報(ビットは、コンピューティングおよびデジタル通信における情報の基本単位です)。
4.圧縮に似ていますが、まったく同じではありません:bitstreams。また、完全なバイトではなく、任意のビット長のフィールドを送信することにより、データストリームのスペースを節約するためにも使用されます。
ここでオープンソース化された高度に最適化されたビットレベルのリーダーとライターのパッケージを書いて公開しました: github.com/icza/bitio 。そのソースでは、あらゆる種類のビット操作の広範な使用法がわかります。
5.別の実用的な使用法:(整数)数の特定のプロパティをテストする。整数のバイナリ表現を知っている( 2の補数 )バイナリ表現には数値の特定の特性があります。たとえば、(2の補数の)整数は、最下位ビットが0の場合、even(2で割ることができます)です。
func isEven(i int) bool {
return i&0x01 == 0
}
整数のビットをテストすることで、2のべき乗かどうかも確認できます。たとえば、正の数に1
ビットが1つしか含まれていない場合は、2のべき乗です(たとえば2 = 0x02 = 00000010b
、16 = 0x10 = 00010000
が、たとえば17 = 0x11 = 00010001
は2のべき乗ではありません。
6.多くのエンコード/デコード手順ビット操作も使用します。最も簡単なのは TF-8エンコーディング です。これは、Unicodeコードポイント(Goのrune
)をバイトシーケンスとして表すために可変長エンコーディングを使用します。
可変長エンコードの簡単なバリエーションは、バイトの最上位ビット(0インデックスの場合は8番目または7番目)を使用して、数字のデコードにさらにバイトが必要かどうかを通知し、残りの7ビット常に「有用な」データです。最上位ビットをテストし、次のように7つの有用なビットを「分離」できます。
b := readOneByte()
usefulBits := b & 0x7f
hasMoreBytes := b & 0x80 != 0
このような可変長エンコーディングを使用する利点は、メモリ内の8バイトであるGoでuint64
タイプを使用しても、少ない数(範囲0..127
1バイトのみが必要です!)。保存または転送するサンプルに多数の小さな値がある場合、これだけでデータを1/8に圧縮できます= 12.5%。欠点は、大きな数値(最上位バイトにビットがある場合もある)が8バイト以上を使用することです。価値があるかどうかは、サンプルのヒューリスティックに依存します。
X.そしてリストが続く...
Go(および他の多くのプログラミング言語)のビット演算子を知らない/使用せずに生きることができますか?答えは「はい」です。しかし、あなたがそれらを知っていれば、時には彼らはあなたの生活を楽にし、あなたのプログラムをより効率的にすることができます。
トピックの詳細を知りたい場合は、Wikipediaの記事 Bitwise operation を読んで、「Bitwise Operators Tutorial」という用語をgoogleで検索してください。多くの優れた記事があります。
彼らが技術的に行うことについては、このコメントをチェックしてください
package main
import "fmt"
func main() {
// Use bitwise OR | to get the bits that are in 1 OR 2
// 1 = 00000001
// 2 = 00000010
// 1 | 2 = 00000011 = 3
fmt.Println(1 | 2)
// Use bitwise OR | to get the bits that are in 1 OR 5
// 1 = 00000001
// 5 = 00000101
// 1 | 5 = 00000101 = 5
fmt.Println(1 | 5)
// Use bitwise XOR ^ to get the bits that are in 3 OR 6 BUT NOT BOTH
// 3 = 00000011
// 6 = 00000110
// 3 ^ 6 = 00000101 = 5
fmt.Println(3 ^ 6)
// Use bitwise AND & to get the bits that are in 3 AND 6
// 3 = 00000011
// 6 = 00000110
// 3 & 6 = 00000010 = 2
fmt.Println(3 & 6)
// Use bit clear AND NOT &^ to get the bits that are in 3 AND NOT 6 (order matters)
// 3 = 00000011
// 6 = 00000110
// 3 &^ 6 = 00000001 = 1
fmt.Println(3 &^ 6)
}
|
のような実際の追加ではないことを示すために、1 + 5
の2つの例を示したことに注意してください。
実際の使用に関しては、他の人がより多くの例でコメントできると確信していますが、1つの一般的な使用は、許可システムのようなもののフラグのビットマスクを作成することです。