組み込み機器から送られてくるデータのパーサーを書いていて、各ビットを取り出すときにビット単位演算の二項演算子(&)とブール演算(and)を間違えて使ってハマってしまったので自戒を込めてここにメモしておきます。Windows10、Python3.6.5で確認しています。
間違いパターン1
2byte(16bit)の値のうち上位10bitの値が有効なのでそれを取り出す
>>> input_val = 0xFF0F # 0b1111111100001111
>>> bit_mask = 0x3FF # 0b0000001111111111
>>> input_val and bit_mask # 間違い!!
1023
>>> bin(input_val and bit_mask)
'0b1111111111'
>>> input_val & bit_mask # 正解
783
>>> bin(input_val & bit_mask)
'0b1100001111'
これは気づきやすい
間違いパターン2
1byte(8bit)の値のうち2bit目の値が欲しいので取り出す
>>> input_val = 0b00000011
>>> bit_mask = 0b00000010
>>> input_val and bit_mask # 処理として間違いだが値としては合ってしまっている
2
>>> bin(input_val and bit_mask)
'0b10'
>>> input_val & bit_mask # 正解
2
>>> bin(input_val & bit_mask)
'0b10'
特に例2の場合は結果だけ見ていると気づきにくい
何が起きているのか
-
ビット単位演算は整数にのみ意味がある処理となっていて、input_valとbit_maskの論理積が実行されます。これは期待している動作ですね。
-
ブール演算ではドキュメントに以下のように説明されています。
式 x and y は、まず x を評価します; x が偽なら x の値を返します; それ以外の場合には、 y の値を評価し、その結果を返します。
なので、andの後にあったbit_maskが評価されて返ってきていたということですね。
所感
- ミスの修正は簡単なのですが、何が起きているか説明しようとするとちゃんとドキュメントを読まないと説明できなかったです。精進しないとですね。
- みなさまも既存のコードでこのようなことをやってないか確認してはいかがでしょうか?(ちなみに私はやらかしてました)
こちらはブール演算について詳しく解説している記事です。参考にさせていただきました。
http://qiita.com/keisuke-nakata/items/e0598b2c13807f102469