原码 反码 補碼#
一:なぜ原码、反码、補碼があるのか?#
計算機が数値をより簡単に計算できるようにするためです。だから計算機は補碼を使用します。
具体的にどう実現するかは後で説明しますが、まず原码、反码、補碼とは何かを見てみましょう。
二:正数の原码、反码、補碼#
インターネット上ではほとんどが原码、反码、補碼をそれぞれ紹介していますが、博主(私)はこの方法が理解しにくいと感じています。だから正数と負数で説明します。
int を基準にすると、0 が多すぎて見にくいので、8 ビットで表現しましょう。
正数は十進数を二進数に変換するだけです。
正数の原码、反码、補碼は同じです
[+1] = [00000001](原码) = [00000001](反码) = [00000001](補碼)
三:負数の原码、反码、補碼#
原码:最上位ビットが1
はこの数が負数であることを示します。
反码: 符号ビットはそのまま
, 他のビットは反転します。
補码: 反码 + 1
[-1] = [10000001](原码) = [11111110](反码) = [11111111](補碼)
四:原码、反码、補碼の意義#
彼らの出現は、計算機がより簡単に計算できるようにするためであり、その結果、性能が向上します。
知識: 1 - 1 = 1 + (-1) だから機械は加算だけで済みます。
まず、原码だけで計算すると、人は符号ビットを簡単に区別できるので、数値を簡単に計算できます。
しかし、計算機が符号ビットを識別するのは非常に面倒です。計算機がより簡単に計算できる方法はないのでしょうか?それで反码が生まれました。
次に、反码の計算を見てみましょう。
1 - 1 = 1 + (-1)
= [0000 0001]原 + [1000 0001]原
= [0000 0001]反 + [1111 1110]反
= [1111 1111]反
= [1000 0000]原
= -0
反码はすでに計算機の計算を簡単にしますが、なぜ補码が必要なのでしょうか。
反码の中で 0 のエンコーディングは [1111 1111] 反 = [-0] と [0000 0000] 反 = [+0] の 2 つです。
正負 0 は意味がないので、補码は 0 の 2 つのエンコーディングの問題を解決するために存在します。
(実際、ここまで反码はどの数を表しているか直接見ることができず、理解が必要です。補码は反码の基礎の上に + 1 を加えるので、さらに理解が難しいです。私はもっと簡単な方法で表現しようとしましたが、問題があればコメントに書いてください。)
補码では:0のエンコーディングは[0000 0000]補 = [+0]
と定められています。
ここでは二進数が表す十進数を考えず、ただエンコーディング
として想像してください。
まず、8 ビットの二進数では、0000 0000 から 1111 1111 までのエンコーディングしかありません(0000 0000 から + 1)。
正数の原码、反码、補码はすべて同じなので、0000 0000 から 0111 1111 を取り除きます。
残りは 1000 0000 から 1111 1111 までの数値で、これらはすべて負数です(符号ビットが 1 だからです)。
これらのエンコーディングを 1 ずつ加えると、次のようになります。
1000 0000
1000 0001
1000 0010
....
1111 1101
1111 1110
1111 1111
まず、これらのエンコーディングが原码であれば、対応する十進数は次のようになります。
-0
-1
-2
....
-125
-126
-127
反码は計算機の計算を便利にするためのものではありませんか?これらのエンコーディングは反码に対応する十進数は次のようになります。
-127
-126
-125
...
-2
-1
-0
-0 があるのはどう解決するのでしょうか?各数から - 1 を引けば、-0 はなくなります。最終的には次のようになります。
-128
-127
-126
...
-3
-2
-1
-0 のエンコーディング問題を完璧に解決し、さらに-128
が追加されました。これが Java で int の値の範囲が $-2^{31}$ ~ $2^{31}-1$ である理由です。
さて、反码がこれらの数にどう変わるのかを考えましょう。
-1 の反码は 1111 1110 で、現在 - 1 のエンコーディング
は 1111 1111 に変わりました(これが - 1 の補码です)。
要するに: 補码=反码+1
補码はこのようにして生まれました。したがって、計算機は補码を使用することで計算をより迅速に実行できます。(反码も可能ですが、-0 の問題があるため、やはり補码を使用します。)