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

> Go 言語（以下 Golang）で、バイトデータの「特定箇所のビット」を確実に `0` にしたい。
> <code>0b10000<font color=red>1</font>00</code> → （マスク: <code>0b<font color=red>1</font>00</code>） → <code>0b10000<font color=red>0</font>00</code>
> <code>0b10000<font color=red>0</font>00</code> → （マスク: <code>0b<font color=red>1</font>00</code>） → <code>0b10000<font color=red>0</font>00</code>
> <code>0b11111<font color=red>1</font>11</code> → （マスク: <code>0b<font color=red>1</font>00</code>） → <code>0b11111<font color=red>0</font>11</code>
>

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

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

## TL; DR <sub><sup>（今北産業）</sup></sub>

1. やりたいことは以下。
    ![スクリーンショット 2023-01-18 9.58.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/78776/8c7470c4-eb38-5144-9b96-f3bf7da9f5cb.png)
1. 具体的には `&^` を使う。例えば `P&^Q`
    - 一見、`&^` が非含意演算子に見えますが、`P & (^Q)` のことです。上記、等価式の `P&¬Q` は `P AND (XOR Q)` という意味です
1. ビットマスクが `1` なら、どんな状態でも `0` にする例
    - <code>0b10000<font color=red>0</font>00 & ^0b<font color=red>1</font>00 = 0b10000<font color=red>0</font>00</code> （`P & ¬Q`）
    - <code>0b10000<font color=red>1</font>00 & ^0b<font color=red>1</font>00 = 0b10000<font color=red>0</font>00</code> （`P & ¬Q`）
    - <code>0b11111<font color=red>1</font>11 & ^0b<font color=red>1</font>00 = 0b11111<font color=red>0</font>11</code> （`P & ¬Q`）

## TL; DR <sub><sup>（Golang のサンプル・コード）</sup></sub>

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

- ビットマスク `0b100` で 2 回 XOR する例
    1. <code>0b10000<font color=red>0</font>00 ^ 0b<font color=red>1</font>00 = 0b10000<font color=red>1</font>00</code> （`P XOR Q = R`）
    2. <code>0b10000<font color=red>1</font>00 ^ 0b<font color=red>1</font>00 = 0b10000<font color=red>0</font>00</code> （`R XOR Q = P`）

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

- ビットマスク `0b11111011` で 2 回 AND する例
    1. <code>0b10000<font color=red>0</font>00 & 0b11111<font color=red>0</font>11 = 0b10000<font color=red>0</font>00</code> （`P AND Q = R`）
    2. <code>0b10000<font color=red>1</font>00 & 0b11111<font color=red>0</font>11 = 0b10000<font color=red>0</font>00</code> （`R AND Q = R`）

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

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

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

```go
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
}
```
- [オンラインで動作をみる](https://go.dev/play/p/9q99eCy--YF) @ GoPlayground