LL脳がscalaの勉強を始めたよ その10


さてコップ本の第5章をやりますよー、ワールドカップのせいでほとんど進んでないですよー

...ということで今回は6節のビット演算です

ビット演算

Scalaのビット演算は次の4つ

  • AND: &
  • OR: |
  • XOR: ^
  • ビット単位補数演算子: ~

さて、ビット演算とかすっかり忘れているので軽くまとめますよー

ちなみにビット演算は2進数で行うみたいなので以下の内容の()内は2進数表記です

AND演算

例えば演算 1 & 2 であれば、1 (0001)、2(0010)の各ビットでANDで行うのです。各ビットという単語は0010の各桁とかで置き換えればわかりやすいですかねぇ(゚∀゚)

AND演算はこんな感じですかねー、基本1がTrueで0がFalseという感じで置き換えると見たことある計算ですな

  • 0 と 0 → 0
  • 1 と 0 → 0
  • 1 と 1 → 1

上記ルールに当てはめると1(0001) & 2(0010) は0(0000)になるわけですな

んじゃScalaで結果をさくっと出して次に進みますー

scala> 1 & 2
res0: Int = 0
OR演算

OR演算もANDと同様に各ビットの比較をORで行う感じです

  • 0 と 0 → 0
  • 1 と 0 → 1
  • 1 と 1 → 1

そんなわけで 1 | 2を例に計算すると、1(0001) | 2(0010)なので3(0011)になるわけですな

こちらもさくっとScala計算してしまいます

scala> 1 | 2
res1: Int = 3
XOR演算

排他的論理和ってやつですね、まるで呪文なので名称は覚えているものの中身についてはいつも忘れてしまうあんちくしょうです

具体例だとあいまいすぎて忘れるので、いっそのこと論理演算で覚えてしまいます

A ^ B = ( A && !B ) || ( !A && B ) 

…とこう書いてしまえば、右側の式で計算することで下のような結果になるわけです

  • A:0、B:0のときは 0
  • A:1、B:0のときは 1
  • A:0、B:1のときは 1
  • A:1、B:1のときは 0

あ、個人的に1をTrue、0をFalseとした方が計算しやすいですねぇ

いちいち計算するがめんどくさければ結果だけ覚えても良さそうですし、「片方だけが真だったら真」っていうざっくりとした暗記でもなんとかなりそうな気が…しませんか?あってるかは不明だけども…

とりあえず1 ^ 2という具体例で計算すると、1(0001) ^ 2(0010)は 3(0011)になりますな

まあ、悩んだらコンソールで計算すればイインダヨ!と開き直って計算します

scala> 1 ^ 2
res2: Int = 3
ビット単位補数演算子

ビット単位補数演算子ってやつは数字の各ビットを反転するのです

例えばIntの1であれば、実際は32bitなので( 00000000000000000000000000000001 )というビット表記の全ての桁を反転して( 1111111111111111111111111111110 )という-2っていう10進数になるわけです。

ちなみに桁の先頭は符号用ビット(1が-で0が+)で、11111111111111111111111111111111が-1で2進数的に数が減っていくと-2,-3と数が小さくなっていって、10000000000000000000000000000000が-2147483648とかになるわけですな…うーんうろ覚えの知識なんで合ってるかなぁ…間違ってたら教えてください(´・ω・`)

まあ、とりあえず計算すれば結果はでるという開き直りで計算してみますー

// 1の補数を計算
scala> ~1   
res4: Int = -2
// -2の補数を計算
scala> ~(-2)
res5: Int = 1

ビットのシフト演算

ビットのシフト演算は次の3種類デス。ちなみにビットをズラす演算デス。

  • 左シフト: <<
  • 右シフト: >>
  • 符号なし右シフト: >>>
左シフト

数字を指定されたビット分左にずらして余ったところに0を突っ込むのが左シフトデス(`・ω・´)キリ、って文字で書いてもよくワカラナイので具体例を書いてみるのデス


桁が多いとわけわかめなので、8bitの00001111を3ビット分左シフトしてみます

  1. 左に3ビットずらします(xは開いたスペースです)
    • 01111xxx
  2. 開いたスペースに0を突っ込みます
    • 01111000

こんな感じで結構強引にビットを動かすわけですねー、動かした後はビットを数値に戻せば欲しい値を求められます。


とりあえず雰囲気はつかめたのでScalaで計算してみますよー

scala> 15 << 3
res7: Int = 120 
右シフト

左シフトでのビット移動方向を右に変えます。ただし、右シフトでは開いたスペースを最上位ビット(符号付き整数だったら符号表現のビット)で埋めてやります。


実際は32bitとかで計算されるんだろうけど、こちらも噛み砕くために8bitの00001111で計算してみますー

  1. 右に3ビットずらします(xは開いたスペースです)
    • xxx00001
  2. 元の数字の最上位ビットは0なので開いたスペースに0を突っ込みます
    • 00000001

こんな感じで動かしたビットを数値に戻せば欲しい値を求められますよー、という感じです。先頭桁の符号が絡んできたりでアレなんで、一応32bitでもやってみますかー

例として-1( 11111111111111111111111111111111)を31bit分右シフトします

  1. 右に31ビットずらします
    • xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1
  2. 元の数字の最上位ビット(符号が-)が1なので、開いたスペースに1を突っ込みます
    • 11111111111111111111111111111111

という塩梅で右シフト後は-1が-1になります。うん、こちらもなんとなく雰囲気がつかめたので計算しますー

scala> -1 >> 31
res12: Int = -1
符号なし右シフト

左シフトは問答無用に0埋めだったのに、右シフトは符号なんかの最上位ビットが影響するのかよ(´・ω・`)という気分になったときは符号なし右シフトです。

こちらが本物の左シフトの右移動版になります、せっかくなので32ビットでやってみましょー

例として-1( 11111111111111111111111111111111)を31bit分符号なし右シフトします

  1. 右に31ビットずらします
    • xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1
  2. 開いたスペースに問答無用で0を突っ込みます
    • 00000000000000000000000000000001

…という感じで出来上がるのは1になるのです…と勢いでScala計算をやってみますよー

scala> -1 >>> 31
res13: Int = 1
いじょー

この節は計算方法さえわかればいいんだろうけども、情報処理試験の復習がてらに詳しくやってみましたとさ…だって普段ビット演算なんかやらないからいつも忘れてしまうのよ(´・ω・`)

次回はオブジェクトの等価性とかからかな…5章終わんのはいつかしら?