ここでは回路ネットワークの算術回路におけるビット演算について解説する。
※回路についての基本的な理解がある事を前提にしています。
2023/02/02更新 「応用:ランプで数字を表示する」追加
導入
ビット演算は便利なもので、シグナル1つで複数の装置を個別にオンオフすることも出来る。
例えば、ケーブルを繋いだベルトA,B,C,Dを制御するとき、シグナルをA~Dまで用意しなくて済む。
解説の前に、これを制御シグナルSのみ、ビット演算なしで制御する方法を考えてみよう。
ベルトA:S = 1 ベルトB:S = 2 ベルトC:S = 3 ベルトD:S = 4
これでは1つしか動かせないので、条件を変えてみる。
ベルトA:S >= 1 ベルトB:S >= 2 ベルトC:S >= 3 ベルトD:S >= 4
これも組み合わせが限定され、Dのみ動かす等が出来ない。
室内灯のスイッチのように、個別に付けたり消したり出来れば…
そういった場合にビットが活躍する。
ビットとは
ビットとは、1つのON/OFFスイッチに置き換えて考えられる情報の単位である。
1ビットとはON/OFFスイッチが1つあるということだ。
ON/OFFは1と0で表される。
ONなら … 1 OFFなら … 0
Factorioで考えた場合、1ビット分の情報(=1もしくは0)があれば1つの装置をON/OFF出来る。
導入の例のように、4つの装置を個別でON/OFFするには4ビット分の情報が必要になる。
4ビットとはON/OFFスイッチが4つなので、以下のようになる。
全てONなら … 1111 全てOFFなら … 0000
これは、2進法で表した4桁の数値として扱うことが出来る。
※2進法 … 1よりも大きい数になると次の桁に繰り上がる記数法
4ビットで表現可能な情報の数は、4つのON/OFFスイッチの状態の組み合わせの数に等しい。
2進数 | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
10進数 | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
※nビット = 2のn乗通り、4ビットでは2*2*2*2 = 16通り
2進数を10進数に直した数値xは、ON/OFFスイッチの組み合わせのx番目と言える
導入の例で言えば、ベルトA,B,C,Dに対して制御シグナルSの(2進数における)1~4桁目を割り当てればよい。
しかし、以下のような設定は適切ではない。
ベルトA:S = 1 ベルトB:S = 10 ベルトC:S = 100 ベルトD:S = 1000
Factorioは数字を全て10進数として扱うため、2進数の値は以下のように10進数に直す必要がある。
ベルトA:S = 1 ベルトB:S = 2 ベルトC:S = 4 ベルトD:S = 8
さらに、制御シグナルSのどの桁がONなのかを判別するために、算術回路のビット演算であるANDを用いる。
ビット演算とは
ビット演算とは、いわば並んだON/OFFスイッチ(=ビット)をいっぺんに操作できる演算のことだ。
Factorioでは算術回路に以下のビット演算子が用意されている。
<<,>>,AND,OR,XOR
<<,>>(左シフト,右シフト)
ビットを左か右にずらす。Factorioでは10進数で指定した桁の数だけずれる。
2進数(指定数は10進数) | 10進数 | 備考 |
---|---|---|
0001 << 3 = 1000 | 1 << 3 = 8 | << 3 なので3桁左にずれる |
1000 >> 2 = 0010 | 8 >> 2 = 2 | >> 2 なので2桁右にずれる |
0010 >> 2 = 0000 | 2 >> 2 = 0 | >> 2 なので2桁右にずれ、はみ出した1は消える |
0011 << 1 = 0110 | 3 << 1 = 6 | << 1 なので1桁左にずれる、1が複数でもそのまま移動される |
AND(論理積)
ANDの左右のビットにおいて、どちらともONのビットを出力する。
2進数 | 10進数 |
---|---|
0101 AND 0011 = 0001 | 5 AND 3 = 1 |
備考:0101に対し、AND 0011は1,2桁目が同じくONである桁のみONにするので1桁目だけがONとなる
OR(論理和)
ORの左右のビットにおいて、どちらかがONのビットを出力する。
2進数 | 10進数 |
---|---|
0101 OR 0011 = 0111 | 5 OR 3 = 7 |
備考:0101は1,3桁目がON、OR 0011は1,2桁目がONであるため、1,2,3桁目がONとなる
XOR(排他的論理和)
XORの左右のビットにおいて、ONかOFFで一致するビットはOFF、異なるビットはONを出力する。
2進数 | 10進数 |
---|---|
0101 XOR 0011 = 0110 | 5 XOR 3 = 6 |
備考:0101とXOR 0011では、1,4桁目はONかOFFで一致しているのでOFF、2,3桁目はONとOFFで異なるのでONとなる
ビット演算を用いた個別制御
ビット演算を用い、制御シグナルSのみでベルトA,B,C,Dを制御する設定は以下の通り。
算術回路1:S AND 1 = S → ベルトA:S = 1 算術回路2:S AND 2 = S → ベルトB:S = 2 算術回路3:S AND 4 = S → ベルトC:S = 4 算術回路4:S AND 8 = S → ベルトD:S = 8
ANDで各桁のON/OFFを検出している。以下のように2進数にすると分かりやすい。
算術回路1:S AND 0001 = S → ベルトA:S = 0001 算術回路2:S AND 0010 = S → ベルトB:S = 0010 算術回路3:S AND 0100 = S → ベルトC:S = 0100 算術回路4:S AND 1000 = S → ベルトD:S = 1000
Sの出力設定例は以下の通り。
条件回路1:任意の条件 出力S(1) → 算術回路A:S << 0 = S ─┬→ ANDの算術回路 条件回路2: 〃 〃 → 算術回路B:S << 1 = S ─┤ 条件回路3: 〃 〃 → 算術回路C:S << 2 = S ─┤ 条件回路4: 〃 〃 → 算術回路D:S << 3 = S ─┘
左シフトで制御するビットの桁を変えて条件回路1~4を上記のベルトA~Dに対応させている。
1つの装置に複数の条件を設定したい場合は、追加条件の出力のみ別のシグナルとORを使う。
ORを使わず、図の条件2~4の出力をまとめて条件回路に繋ぐことでも同じ動作が出来る。
条件2~4の出力 → 条件回路:S > 0 出力S(1) → 算術回路:S << 1 = S → ANDの算術回路
応用:ランプで数字を表示する
2016年2月25日はFactorioがSteamで早期アクセスとしてリリースされた日である
この項ではランプとビット演算を用いて、アラビア数字を表示する7セグメントディスプレイの実装方法を説明する。
用いるのはランプのほか算術回路1つ、定数回路1つと非常にコンパクトになっている。
※参考リンク
wikipedia - 7セグメントディスプレイ
Simplest 7-segment display possible - 0-9 displayed with one arithmetic and one constant combinator
概要
この実装では信号の値の最上位のビットによってランプを制御する方法を用いる。
Factorioの信号の値は32ビット符号付き整数であり、最上位のビットによって値の正負が分かれている。
10進数 | 2進数 |
---|---|
2147483647 | 0111 1111 1111 1111 1111 1111 1111 1111 |
-2147483648 | 1000 0000 0000 0000 0000 0000 0000 0000 |
ランプの条件:信号 < 0 とすると以下のようになる。
値が0以上 → 最上位ビットが0、ランプは点灯しない 値が0よりも小さい → 最上位ビットが1、ランプは点灯する
次に、7セグメント分の信号の上位ビットから順に作動条件を10ビット分(=0~9)2進数で埋め込む。
あとは信号を左シフトする数により、どのビットを最上位ビットとするかを制御すればよい。
実装例
概略図
定数回路にセグメントにあたる信号A~Gを以下の通り設定し、算術回路に接続する。
信号 | 32ビットバイナリ(2進数) | 32ビット符号付き整数 |
---|---|---|
A | 1011 0111 1100 0000 0000 0000 0000 0000 | -1212153856 |
B | 1000 1110 1100 0000 0000 0000 0000 0000 | -1900019712 |
C | 1111 1001 1100 0000 0000 0000 0000 0000 | -104857600 |
D | 0011 1110 1100 0000 0000 0000 0000 0000 | 1052770304 |
E | 1010 0010 1000 0000 0000 0000 0000 0000 | -1568669696 |
F | 1101 1111 1100 0000 0000 0000 0000 0000 | -541065216 |
G | 1011 0110 1100 0000 0000 0000 0000 0000 | -1228931072 |
算術回路はEach(黄*)<< X 出力:Eachとし、出力を全てのランプに接続する。
ランプの設定は、概略図のように各位置に対応する信号に対して0未満で作動とする。
算術回路に信号X(値:0~9)を入力すると、数字に対応してランプが点灯する。
セグメントを増やすには、信号の種類を増やし、同じように2進数で作動条件を決め、10進数で定数回路に出力させればよい。
※2進数の変換に便利なサイト
2,8,10,16進数 計算・変換(マイナス、小数点対応)
0eNrdmG1rqzAUx7/KyGs7kmgSlb65d09fYXApxdpsC/hEjOOW4ne/id3UumatgoNehNJo8s/JL+ecPOzBJql4IUWmQLgHIs6zEoR/9qAUr1mUmHdqV3AQAqF4ChyQRakplWmUJIskSgtQO0BkW/4XhKh2zjaMpFBvKVciXsR5uhFZpHLZ08D1ygE8U0IJfrCkKezWWZVuuNSdnLLBAUVe6iZ5ZjrWMgsEA++WOGCn/3s+vSW6Cz04JfNkveFv0bvQ3eq6sZBxJdRaf9u2Ai9Clmr9ZSTvQqpKv+ksaGosfoODeKkigxGaQlpEshlaCJbmc1Vy3UeSSz0oJSt+aJHx2PRZmk6Q+XmVnGf9YYstCF3DtVcm9aque+8+0eCL0eAODZsVza8fRuNZ0LgXo3H/FzRogAZb0HgXo0E/FVB3M6PBAzS+BQ2ZkmvIVeeaodcwCxo6Jdd4s6K5nxkNG6BBtohiU5LNdbOhX5ao43JgQeVPST7kqpOPbYkKpiQbd1YUDz8dUdDCBsEpcPBVwwmGcFwbHDQliOaF8zj3MmXLvQhPgeFeNYxh8kXIBmfSNhjNCudpbk+BQzq2BIy8KXuaK6czPEAhPbBPw787NSBy5kh/2qs+qLGgobYV8mBls588xbDT7jCWEzjyKH4zrEpuZC5v92wa5QXXwBszwXKp6+SVKqrRvdejJoZq8A7A9gpWN+625p+Oc3ZeYOvPF8/Mi0gUl5bLojNn3sr48gJh/RDXJ/TMDdKZs9CHWgAhRAEzC0B7lzRG7e5IDeptJqMQtmLuKLH7nhiCBDMGXei1Yt4osYcjywj1KQ3006qRUWqPfTXiIUgJRp0YHSX2dDyh2A9cBFk3BWyU2nNPLWg1/CYSLo+cQQY7LIYr53ARGfYuPB2QRBuuDQPspuSvqRa52YqySKKd/vauvbsJAOwjHRaYUUp86vt1/Q9fCCYl