0
0

【Golang】ビット演算で特定ビットを反転ではなく 0 にする【ビットの非含意(P ⊅ Q)】

Last updated at Posted at 2023-01-18

Go 言語(以下 Golang)で、バイトデータの「特定箇所のビット」を確実に 0 にしたい。
0b10000100 → (マスク: 0b100) → 0b10000000
0b10000000 → (マスク: 0b100) → 0b10000000
0b11111111 → (マスク: 0b100) → 0b11111011

つまり、スイッチを下げるがごとく、ビットマスクが 1 なら、どのような状態であっても 0 にしたいのです。

いわゆるひとつの、論理演算における「非含意ひがんい」(P ⊅ Q)をしたいのです(ゆうて、そんな名前が付いてるって知らんかったけど)。

TL; DR (今北産業)

  1. やりたいことは以下。
    スクリーンショット 2023-01-18 9.58.14.png
  2. 具体的には &^ を使う。例えば P&^Q
    • 一見、&^ が非含意演算子に見えますが、P & (^Q) のことです。上記、等価式の P&¬QP AND (XOR Q) という意味です
  3. ビットマスクが 1 なら、どんな状態でも 0 にする例
    • 0b10000000 & ^0b100 = 0b10000000P & ¬Q
    • 0b10000100 & ^0b100 = 0b10000000P & ¬Q
    • 0b11111111 & ^0b100 = 0b11111011P & ¬Q

TL; DR (Golang のサンプル・コード)

10 に反転させたいからと、単純にマスクを XOR 演算(^、排他的論理和)して反転させるも、2 回適用すると 1 に戻ってしまいます。

  • ビットマスク 0b100 で 2 回 XOR する例
    1. 0b10000000 ^ 0b100 = 0b10000100P XOR Q = R
    2. 0b10000100 ^ 0b100 = 0b10000000R XOR Q = P

... ... まぁ、「反転」なので当然です。一般的には「反転させたい値と同じ長さの逆のマスク」を AND 演算(&)します。

  • ビットマスク 0b11111011 で 2 回 AND する例
    1. 0b10000000 & 0b11111011 = 0b10000000P AND Q = R
    2. 0b10000100 & 0b11111011 = 0b10000000R AND Q = R

問題は、ビットマスクを 0b100 の形で指定したいのです。

「それならば、マスクを ^XOR)してから、& すればいいじゃない」と、A & (^B) と B を反転させてから XOR すればいいだけでした。

そして、処理優先度が ^ の方が & より上(^ > &)なので A&^B(= A & ^B) で落ち着きました。あっちょんぶりけ。

package main

import "fmt"

func Example() {
	const (
		input1 = 0b10000000
		input2 = 0b10001000
		mask   = 0b00001000
	)

	// AND
	fmt.Printf("%08b AND %08b = %08b\n", input1, mask, input1&mask)
	fmt.Printf("%08b AND %08b = %08b\n", input2, mask, input2&mask)

	// XOR
	fmt.Printf("%08b XOR %08b = %08b\n", input1, mask, input1^mask)
	fmt.Printf("%08b XOR %08b = %08b\n", input2, mask, input2^mask)

	// AND XOR
	fmt.Printf("%08b AND XOR %08b = %08b\n", input1, mask, input1&^mask)
	fmt.Printf("%08b AND XOR %08b = %08b\n", input2, mask, input2&^mask)

    // 右から 4 ビット目の動きに注目
    //
	// Output:
	// 10000000 AND 00001000 = 00000000
	// 10001000 AND 00001000 = 00001000
	// 10000000 XOR 00001000 = 10001000
	// 10001000 XOR 00001000 = 10000000
	// 10000000 AND XOR 00001000 = 10000000
	// 10001000 AND XOR 00001000 = 10000000
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0