Pythonでコンピュータを作る#5 -NANDは全ての論理ゲート-

暑くて半分溶けている大学生の[Motmuu](https://qiita.com/Motmuu)です.
これまでパーセプトロンというアルゴリズムを用いて論理ゲートを実装してきました.
はい??っと思った方はこちらからご覧ください

・#1 [アルゴリズムとは](https://qiita.com/Motmuu/items/ed28e729b863103db089)
・#2 [パーセプトロンとは](https://qiita.com/Motmuu/items/69b3b26afd261484ede9)
・#3 [単純な論理回路](https://qiita.com/Motmuu/items/1f4de21cd4fdbc9a3836)
・#4 [XORゲート](https://qiita.com/Motmuu/items/64bc5106841cb443107a)

今日は,NANDゲートを用いて他の論理ゲートを作ってみよう！というちょっとしたコーヒーブレイクです笑

#開発環境
以下の環境で勉強していきたいと思います.
`・Python 3.6.5
・Mac OS X 10.13.2
・Atom 1.10.2`

サンプルコードは[こちら](https://github.com/MotoyaKondo/qitta_gates)
#ANDゲート
NANDゲートはANDゲートの反対のイメージですね.
真理値表を比較すると以下のようになります

|x1|x2|AND |NAND|
|:-:|:-:|:-:|:-:|
| 0 | 0  | 0  |1|
|  0 | 1  | 0  |1|
|  1 | 0  |  0 |1|
|  1 | 1  |  1 |0|

ではNANDの否定をとれば,ANDになりますね
では否定しましょう！ ...そういえばNOTゲート忘れていましたね.
では否定を取るNOTゲートをPythonで実装しましょう

#NOTゲート
NOTゲートはその通り否定です.1入力1出力で1が入力されれば0が0が入力されれば1を出力します.
あーいえばこういう,ちょっと嫌なやつですね.
これをNANDゲートを用いて再現します.
コードは以下の通りです.

```python
gates/NOT.py

#インポート
fromt gates import NAND

# NOTをクラスとして作成
class NOT():
    def __new__(self,a):
        return NAND.NAND(a,a) #今回はNOTゲートをNANDゲートを用いて実装しました.

# 実際に真理値表のようになるか確かめてみる

print(NOT(0))
print(NOT(1))

```

Terminalでの実行けかは以下のようになりました.

```terminal
*********$ python NOT.py
1
0
```

友達にはなりたくないですが,このNOTゲートはとてもやくにたちます!
それでは気を取り直してANDゲートを実装していきましょう

#気を取り直してANDゲート
Pythonでのコードは以下のようになります.

```python
play.py

# 論理ゲートをインポート
from gates import AND
from gates import NAND
from gates import OR
from gates import NOR
from gates import XOR
from gates import NOT

# ANDゲート
print(NOT.NOT(NAND.NAND(0,0)))
print(NOT.NOT(NAND.NAND(0,1)))
print(NOT.NOT(NAND.NAND(1,0)))
print(NOT.NOT(NAND.NAND(1,1)))
```

出力は以下のようになります.

```terminal
********$ python play.py
0
0
0
1
```
実装できました.同様にORゲート,XORゲートも実装していきましょう

#ORゲート

真理値表は以下のようになります.

| x1 | x2 | NAND | OR | 
|:-:|:-:|:-:|:-:|
| 0  | 0  | 1  | 0  |   
| 0  | 1  | 1  | 1  |   
| 1  | 0  | 1  | 1  |   
| 1  | 1  | 0  | 1  |   

じっくり見てみると,ORとNANDはなんとなく近い気がします.くるっと反転できればいいなって感じですね.
ではx1とx２の入力を反転させてからNANDをとったらどうでしょうか.

| x1 | x2 | NOT x1 | NOT x2 | NAND | OR |
|:-:|:-:|:-:|:-:|:-:|:-:|
| 0  | 0  | 1  | 1  | 0  | 0  |
| 0  | 1  | 1  | 0  | 1  | 1  |
| 1  | 0  | 0  | 1  | 1  | 1  |
| 1  | 1  | 0  | 0  | 1  | 1  |

見事に一致しました.
ではPythonで実装しましょう.

```python
play.py

# 論理ゲートをインポート
from gates import AND
from gates import NAND
from gates import OR
from gates import NOR
from gates import XOR
from gates import NOT

#ORゲート
print(NAND.NAND(NOT.NOT(0),NOT.NOT(0))) #(0,0)
print(NAND.NAND(NOT.NOT(0),NOT.NOT(1))) #(0,1)
print(NAND.NAND(NOT.NOT(1),NOT.NOT(0))) #(1,0)
print(NAND.NAND(NOT.NOT(1),NOT.NOT(1))) #(1,1)
```

出力です.

```terminal
********$ python play.py
0
1
1
1
```
できましたね.
これを否定することで,NORゲートも実装できますね.

#XORゲート

前回やったようにXORゲートはNANDゲート,ORゲート,ANDゲートで表せました.
すなわち同様にすれば,NANDゲートで表せることができるはずです.

```python
play.py

# 論理ゲートをインポート
from gates import AND
from gates import NAND
from gates import OR
from gates import NOR
from gates import XOR
from gates import NOT

#XORゲート
print(NOT.NOT(NAND.NAND(NAND.NAND(0,0),NAND.NAND(NOT.NOT(0),NOT.NOT(0))))) #(0,0)
print(NOT.NOT(NAND.NAND(NAND.NAND(0,1),NAND.NAND(NOT.NOT(0),NOT.NOT(1))))) #(0,1)
print(NOT.NOT(NAND.NAND(NAND.NAND(1,0),NAND.NAND(NOT.NOT(1),NOT.NOT(0))))) #(1,0)
print(NOT.NOT(NAND.NAND(NAND.NAND(1,1),NAND.NAND(NOT.NOT(1),NOT.NOT(1))))) #(1,1)
```
出力です.

```terminal
********$ python play.py
0
1
1
0
```

なんだかごちゃごちゃしていますができましたね.

#なんでNAND??
最後のXORといい全てNAND表せることはわかりましが,ごちゃごちゃしていて必要性をあまり感じないかもしれません.でも全てNANDで表せるということはNANDさえ作れればいいということになります.
これは,ハード面で実際にコンピュータを作るときに非常に便利です.NANDだけ作れば他の論理回路が作れるのですから.

#まとめ
全ての論理回路はNANDゲートで表せることがわかりました.
次からはマイクロプロセッサ内での記憶装置,演算装置を論理回路で再現して行きます!

次はこちら -> #6 [記憶装置](https://qiita.com/Motmuu/items/c80dbc14b17f9d79206b)