イチケンさんの Youtube 動画を見ていたら「NAND ゲートだけの組み合わせで NOT/AND/OR/NOR が作れる」と知り、過去に書いたソフトウェア加算器を書き直してみました。動画では触れられていませんでしたが、XOR もちゃんと作れるみたい。
#include <stdio.h>
#define NBBITS 8
/* 論理ゲート */
int _nand(int a, int b) { return (!a && !b) || (!a && b) || (a && !b); }
int _not(int a) { return _nand(a, a); }
int _and(int a, int b) { return _not(_nand(a, b)); }
int _or(int a, int b) { return _nand(_nand(a, a), _nand(b, b)); }
int _nor(int a, int b) { return _not(_or(a, b)); }
int _xor(int a, int b) { return _nand(_nand(a, _nand(a, b)), _nand(b, _nand(a, b))); }
/* 半加算器 */
int half_adder(int a, int b, int* res)
{
*res = _xor(a, b);
return _and(a, b); // carry
}
/* 全加算器 */
int full_adder(int a, int b, int carry, int* res)
{
int carry1 = half_adder(a, b, res);
int carry2 = half_adder(*res, carry, res);
return _or(carry1, carry2); // carry
}
/* 複数ビット加算器 */
void multibit_adder(int a[], int b[], int res[])
{
int carry;
for (int i = 0; i < NBBITS; i++) {
if (i) {
carry = full_adder(a[i], b[i], carry, &res[i]);
}
else {
carry = half_adder(a[i], b[i], &res[i]);
}
}
}
/* 複数ビット減算器 */
void multibit_subber(int a[], int b[], int res[])
{
int carry = 1;
for (int i = 0; i < NBBITS; i++) {
carry = full_adder(a[i], _not(b[i]), carry, &res[i]);
}
}
/* 内容を印字する(左が小さい桁) */
void dump(int a[])
{
for (int i = 0; i < NBBITS; i++) { printf("%d", a[i]); }
puts("");
}
int main()
{
/* 左が小さい桁 */
int a[] = {1, 0, 0, 0, 0, 0, 0, 0};
int b[] = {0, 1, 0, 0, 0, 0, 0, 0};
int res[] = {0, 0, 0, 0, 0, 0, 0, 0};
puts("a + b =");
multibit_adder(a, b, res);
dump(a);
dump(b);
dump(res);
puts("");
puts("a - b =");
multibit_subber(a, b, res);
dump(a);
dump(b);
dump(res);
puts("");
return 0;
}
加算器を作るだけだったら、NOR ゲートは不要ですがついでに実装。10進数で表現すると、a = 1
, b = 2
となります。出力は次のとおり。
a + b =
10000000
01000000
11000000
a - b =
10000000
01000000
11111111
2進数の列は左が小さい桁です。
1 - 2
がちゃんとマイナス値になっているのが楽しい。コンピューターで何故 0xFF
が -1 として扱われるか、よく分かりますね。