Go言語 big.Int.Bit() を活用したビット操作のプログラミング例集
2025-06-01
- 戻り値
uint
: 指定されたビット位置i
の値(0 または 1)をuint
型で返します。 Bit(i int)
:big.Int
型のメソッドの一つです。引数として非負の整数i
を取ります。このi
はビットの位置(インデックス)を表します。big.Int
型: Go 言語のmath/big
パッケージで提供される型で、標準のint
型よりも大きな整数値を扱うことができます。
ビット位置の数え方
ビット位置は、右端のビットから 0 として数え始めます。
- 例えば、整数値が 6 (バイナリで
110
) の場合:Bit(0)
は右端のビットなので0
を返します。Bit(1)
は右から 2番目のビットなので1
を返します。Bit(2)
は右から 3番目のビットなので1
を返します。Bit(3)
より左のビットは0
とみなされ、Bit(3)
は0
を返します。
例
package main
import (
"fmt"
"math/big"
)
func main() {
n := big.NewInt(6) // 整数値 6 を持つ big.Int を作成 (バイナリ: 110)
fmt.Println(n.Bit(0)) // 出力: 0 (右端のビット)
fmt.Println(n.Bit(1)) // 出力: 1 (右から2番目のビット)
fmt.Println(n.Bit(2)) // 出力: 1 (右から3番目のビット)
fmt.Println(n.Bit(3)) // 出力: 0 (指定した位置より左のビット)
fmt.Println(n.Bit(100)) // 出力: 0 (大きなインデックスを指定した場合も 0)
}
例1: 特定のビットが立っているかどうかの確認
この例では、big.Int
型の数値の特定のビット位置が 1 であるかどうかを確認します。
package main
import (
"fmt"
"math/big"
)
func main() {
n := big.NewInt(13) // 整数値 13 (バイナリ: 1101)
bitPosition := 2 // 確認したいビット位置 (右から 3番目)
if n.Bit(bitPosition) == 1 {
fmt.Printf("%d の %d ビット目は立っています (1)\n", n, bitPosition)
} else {
fmt.Printf("%d の %d ビット目は立っていません (0)\n", n, bitPosition)
}
bitPosition = 0 // 確認したいビット位置 (右端)
if n.Bit(bitPosition) == 1 {
fmt.Printf("%d の %d ビット目は立っています (1)\n", n, bitPosition)
} else {
fmt.Printf("%d の %d ビット目は立っていません (0)\n", n, bitPosition)
}
}
解説
if
文で、返されたビット値が 1 であるかどうかを判定し、結果を出力します。n.Bit(bitPosition)
は、指定されたビット位置の値(0 または 1)を返します。bitPosition
変数で確認したいビットの位置を指定します。ビット位置は右端から 0 で始まることに注意してください。big.NewInt(13)
で、値が 13 のbig.Int
型の変数n
を作成します。13 をバイナリで表現すると1101
です。
例2: big.Int
のすべてのビットを走査して表示
この例では、big.Int
型の数値のすべてのビットを走査し、それぞれのビットの値と位置を表示します。BitLen()
メソッドを使って、big.Int
の有効なビット長を取得します。
package main
import (
"fmt"
"math/big"
)
func main() {
n := big.NewInt(42) // 整数値 42 (バイナリ: 101010)
bitLength := n.BitLen()
fmt.Printf("%d のビット:\n", n)
for i := 0; i < bitLength; i++ {
bitValue := n.Bit(i)
fmt.Printf("ビット位置 %d: %d\n", i, bitValue)
}
}
解説
for
ループで、0 からbitLength - 1
までのインデックスでn.Bit(i)
を呼び出し、各ビットの値を取得して表示します。n.BitLen()
は、n
の最上位ビットのインデックス + 1、つまり有効なビット数を返します。big.NewInt(42)
で、値が 42 のbig.Int
型の変数n
を作成します。42 をバイナリで表現すると101010
です。
例3: ビット演算と Bit()
の組み合わせ
この例では、ビット演算の結果として得られた big.Int
の特定のビットを確認します。
package main
import (
"fmt"
"math/big"
)
func main() {
a := big.NewInt(5) // 整数値 5 (バイナリ: 101)
b := big.NewInt(3) // 整数値 3 (バイナリ: 011)
// AND 演算
andResult := new(big.Int).And(a, b) // 結果: 001 (1)
fmt.Printf("%d AND %d = %d (バイナリ: %b)\n", a, b, andResult, andResult)
fmt.Printf("AND 結果の 0 ビット目: %d\n", andResult.Bit(0)) // 出力: 1
fmt.Printf("AND 結果の 1 ビット目: %d\n", andResult.Bit(1)) // 出力: 0
// OR 演算
orResult := new(big.Int).Or(a, b) // 結果: 111 (7)
fmt.Printf("%d OR %d = %d (バイナリ: %b)\n", a, b, orResult, orResult)
fmt.Printf("OR 結果の 0 ビット目: %d\n", orResult.Bit(0)) // 出力: 1
fmt.Printf("OR 結果の 1 ビット目: %d\n", orResult.Bit(1)) // 出力: 1
fmt.Printf("OR 結果の 2 ビット目: %d\n", orResult.Bit(2)) // 出力: 1
}
%b
フォーマット指定子を使うと、big.Int
の値をバイナリ形式で出力できます。- その後、
Bit()
メソッドを使って、演算結果の特定のビットの値を確認しています。 new(big.Int).And(a, b)
やnew(big.Int).Or(a, b)
は、それぞれビットごとの AND 演算と OR 演算を行い、その結果を新しいbig.Int
型の変数に格納します。big.NewInt()
で二つのbig.Int
型の変数a
とb
を初期化します。
big.Int.Bits() メソッド (ビット列への直接アクセス)
big.Int.Bits()
メソッドは、big.Int
の内部表現である[]uint
型のスライスを返します。このスライスは、big.Int
の絶対値をリトルエンディアン(最下位のワードが最初の要素)で表現したワードの配列です。各ワードは通常、32 ビットまたは 64 ビットの符号なし整数です。
package main
import (
"fmt"
"math/big"
)
func main() {
n := big.NewInt(13) // 整数値 13 (バイナリ: ...0000 1101)
bits := n.Bits()
fmt.Printf("内部ビット表現: %v\n", bits)
// 特定のビット位置へのアクセス (少し複雑になります)
bitIndex := 2 // 確認したいビット位置
wordIndex := bitIndex / 32 // 通常のワードサイズを仮定
bitInWord := uint(bitIndex % 32)
if wordIndex < len(bits) && (bits[wordIndex]&(1<<bitInWord)) != 0 {
fmt.Printf("%d の %d ビット目は立っています (1)\n", n, bitIndex)
} else {
fmt.Printf("%d の %d ビット目は立っていません (0)\n", n, bitIndex)
}
}
解説
- ビットが立っているかどうかは、ワードの値とビットマスク (
1<<bitInWord
) の論理 AND 演算の結果が 0 でないかで判定します。 - ビット位置
bitIndex
を、対応するワードのインデックスwordIndex
と、そのワード内のビット位置bitInWord
に変換する必要があります。 n.Bits()
は、n
の内部表現のスライスを返します。
注意点
big.Int
の内部表現は Go のバージョンやアーキテクチャによって異なる可能性があるため、この方法を直接利用する場合は注意が必要です。
ビットマスクと論理演算
package main
import (
"fmt"
"math/big"
)
func main() {
n := big.NewInt(13) // 整数値 13 (バイナリ: ...0000 1101)
// 下位 3 ビットの状態を確認
mask := big.NewInt(7) // バイナリ: ...0000 0111
lower3Bits := new(big.Int).And(n, mask)
fmt.Printf("%d の下位 3 ビット: %d (バイナリ: %b)\n", n, lower3Bits, lower3Bits)
// 特定のビットがすべて立っているか確認
checkMask := big.NewInt(6) // 確認したいビット位置に対応するマスク (バイナリ: ...0000 0110)
if new(big.Int).And(n, checkMask).Cmp(checkMask) == 0 {
fmt.Printf("%d の 1 ビット目と 2 ビット目は両方立っています\n", n)
} else {
fmt.Printf("%d の 1 ビット目と 2 ビット目の少なくとも一方は立っていません\n", n)
}
}
解説
Cmp()
メソッドは、big.Int
同士を比較するために使用します。- ビットマスクを作成し、
And()
などの論理演算メソッドを使って、特定のビット範囲の値を取得したり、特定のビットが立っているかどうかを判定したりします。
文字列変換 (Format() メソッド)
big.Int
をバイナリ文字列に変換し、その文字列を解析することで、各ビットの値を確認できます。
package main
import (
"fmt"
"math/big"
)
func main() {
n := big.NewInt(13) // 整数値 13
binaryString := n.Format(nil, 2) // 2進数文字列に変換
fmt.Printf("%d のバイナリ表現: %s\n", n, binaryString)
// 文字列のインデックスでビット値にアクセス (右端がインデックス 0 にならない点に注意)
bitIndexFromRight := 2
bitIndexFromLeft := len(binaryString) - 1 - bitIndexFromRight
if bitIndexFromLeft >= 0 && bitIndexFromLeft < len(binaryString) && binaryString[bitIndexFromLeft] == '1' {
fmt.Printf("%d の右から %d ビット目は立っています (1)\n", n, bitIndexFromRight)
} else {
fmt.Printf("%d の右から %d ビット目は立っていません (0)\n", n, bitIndexFromRight)
}
}
解説
- バイナリ文字列のインデックスを使って、特定のビット位置の値にアクセスできます。ただし、文字列のインデックスは左端から始まるため、右端からのビット位置を考慮してインデックスを計算する必要があります。
n.Format(nil, 2)
は、big.Int
n
をバイナリ形式の文字列に変換します。