コンピュータの原コード、逆コード、補コードの詳しい解


注:前に原コード、逆コード、補コードに関する資料を探しましたが、張子秋のブログ:原コード、逆コード、補コードの詳細はよく説明されています.便宜上、ここに転載し、著作権は原作者の所有とする.より深い分析は、著者の原文を参考にすることができる.
本文の大部分の内容はこれに由来する.後に「大数オーバーフロー」についての質問があります.
作者:张子秋出典:http://www.cnblogs.com/zhangziqiu/
マシン数と真値
マシン数
コンピュータにおける1つの数のバイナリ表現形式を、この数の機械数と呼ぶ.機械数は記号付きで、コンピュータに1つの数の最高位で記号を保存し、正数は0、負数は1である.
例えば、十進法の数+3、計算機の文字長は8ビットで、バイナリに変換すると0000011になります.-3なら10000011です.では、ここの0000011と10000001がマシン数です.
真の値
1番目がシンボルビットであるため,マシン数の形式値は真の数値に等しくない.例えば、上には符号数10000011があり、その最上位1は負を表し、その真の数値は-3であり、形式値131ではない(10000011は10進数131に変換される).したがって,区別のために,符号ビット付きのマシン数に対応する真の数値をマシン数の真値と呼ぶ.
例:0000 0001の真の値=+000 0001=+1000 0001の真の値=–000 0001=–1
オリジナルコード
元のコードは、シンボルビットに真の値を加えた絶対値であり、すなわち、最初のビットでシンボルを表し、残りのビットで値を表す.例えば、8ビットのバイナリであれば、
[+1]原=0000 0001
[-1]原=1000,0001
第1ビットはシンボルビットである.第1ビットはシンボルビットであるため,8ビットのバイナリ数の値範囲は次のようになる.
[111,1111,0111,1111],すなわち:
[-127 , 127]
原コードは人間の脳が最も理解しやすく計算しやすい表現である.
ぎゃくコード
逆符号の表現方法は、正数の逆符号がそれ自体である.の逆符号は、その元の符号に基づいて、記号ビットは変わらず、残りの各ビットは逆をとる.
[+1]=[00000001]原=[000000001]逆
[-1]=[1000001]元=[1111111110]逆
逆符号が負数を表す場合、人間の脳はその数値を直感的に見ることができず、通常は元の符号に変換して計算しなければならない.
ほすう
符号化の表現方法は、正数の符号化がそれ自体である.の補符号はその元の符号の基礎の上で、記号のビットは不変で、残りの各位は逆を取って、最後に+1.(つまり逆符号の基礎の上で+1)
[+1]=[00000001]原=[000000001]反=[000001]補
[-1]=[1000001]原=[1111111110]反=[1111111111]補
負の数についても、補符号の表示方式は人間の脳ではその数値を直感的に見ることができない.通常は原符号に変換してその数値を計算する必要がある.
なぜ元のコード、逆コード、補コードを使うのか
深く勉強する前に、私の学習提案はまず「硬背を死記する」上の原コード、逆コードと補コードの表現方式と計算方法である.
コンピュータは3つの符号化方式で1つの数を表すことができることが分かった.正数については3つの符号化方式の結果が同じであるからだ.
[+1]=[00000001]原=[000000001]反=[000001]補
あまり説明する必要はありませんが、負数については:
[-1]=[1000001]原=[1111111110]反=[1111111111]補
原号は人の脳に直接認識され、表現を計算するために使われている以上、なぜ逆符号と補符号があるのだろうか.
まず、人間の脳は第一位がシンボルビットであることを知ることができるので、計算する時、私達はシンボルビットに基づいて、真値領域に対する加減を選択します.設計をできるだけ簡単にしなければならない.コンピュータ識別「シンボルビット」は明らかにコンピュータの基礎回路設計を非常に複雑にする.そこで、符号ビットも演算に関与する方法が考案され、演算法則に基づいて正数を減算することは、1-1=1+(-1)=0を加算することに等しいので、機械は加算のみで減算することができ、コンピュータ演算の設計がより簡単になることが分かった.
そこで人々はシンボルビットを演算に参加させ,加算のみを残す方法を探求し始めた.まず原コードを見る.10進数を計算する式:1-1=0
1-1=1+(-1)=[000000001]原+[1000001]原=[100000010]原=-2
符号で表すと、符号ビットも計算に参加させることは、減算にとって結果が正しくないことは明らかである.これは、コンピュータ内部で符号を用いて数を表さない理由である.
原コードを減算する問題を解決するために、逆コードが発生した.10進数を計算する式:
1-1=0
1−1=1+(−1)=[0000 0001]原+[1000 0001]原=[0000 0001]逆+[111 1110]逆=[111 1111]逆=[1000 0000]原=−0
減算を逆符号で計算すると、結果の真の値の部分が正しいことが分かった.唯一の問題は「0」という特殊な数値にある.+0と-0は同じであることは理解されているが、0バンド記号には何の意味もない.また、「00000」元と「1000,000」元の2つの符号が0を表す.
そこで符号化の出現は、0の記号と2つの符号化の問題を解決した.
1−1=1+(−1)=[00000]原+[1000,0001]原=[0000,0001]補+[111,111]補=[0000,000]補=[0000,000]原
このように0は[00000]で表されるが、以前に問題があった-0は存在しない.また、[1000,000]で-128:を表すことができる.
(-1)+(-127)=[1000,000]原+[111,1111]原=[111,1111]補+[100,000]補=[100,000]補
-1-127の結果は-128であるべきであり、符号化演算の結果では、[1000,000]が-128であることに注意するが、実際には以前の-0の符号化を用いて-128を表すため、-128には元符号と逆符号の表示はない.(-128の符号化に対して[100,000]が加算された元符号は[000,000]元であり、これは正しくない)
補数を用いることで、0の符号および2つの符号化の問題を修復するだけでなく、1つの最低数を多く表すことができる.これは、8ビットバイナリが、元の符号または逆符号で表す範囲が[-127,+127]であり、補数で表す範囲が[-128,127]である理由である.
マシンは、符号化を用いるので、プログラムでよく用いられる32ビットintタイプについては、[-231,231-1]の範囲を表すことができる.1ビット目は符号ビットを表すため、符号化表示を用いる場合は最小値を1つ多く保存することができる.
符号表示のオーバーフロー問題
以下は本人の補足の理解で、正しいかどうか分かりません.
コンピュータ内の数字は、例えば、8 bitのbyteタイプの表現範囲は、
[-128, 127]
0=[00000](補足)
-128=[1000,000](補完)
127=[011111](補)
byteタイプの変数が上限127を超えた場合、次のようになります.
+128=-(-128)=127+1=[111,111](補完)+[0001](補完)=[1000,000](補完)=[128]
+129=127+2=[111,1111](補)+[0000,0001](補)=[1000,0001](補)=[111,1111](原)=-127
byteタイプの変数が下限-128を超えた場合:
-129=-128-1=[1000,000](補完)-[000,000](補完)=[011111](補完)=127
-130=-128-2=[1000,000](補完)-[00,000,000](補完)=[0111,110](補完)=126
byte a = -128, b = (byte) 128, c = (byte) 129, d = (byte) 130;
byte e = (byte) -129, f = (byte) -130;
System.out.println(a == ((byte)-a));    // true
System.out.println(b);  // -128
System.out.println(c);  // -127
System.out.println(d);  // -126
System.out.println(e);  // 127
System.out.println(f);  // 126

大数オーバーフロー問題
intタイプは32ビットシステムにおいて4バイト、32 bitを占め、符号化表現のデータ範囲は以下の通りである.
[10000000 00000000 00000000 00000000] ~ [01111111 11111111 11111111 11111111]
[−231,231−1]
[-2147483648, 2147483647]
Javaでは次のように表されます.[Integer.MIN_VALUE, Integer.MAX_VALUE]
byteタイプの表示と同様に、負数が正数よりも多いので1つの数字を表しています.下限に対して逆数を除いた値は上限値を超えて下限にあふれますので、下限の逆数は下限と等しいです.上限に対して逆数を除いた値は負で、この負の値は下限の負の値より1大きく、表すことができる範囲内なので、上限の逆数は上限で直接負の値をとります.
// 2147483647   [01111111 11111111 11111111 11111111]
System.out.println(Integer.MAX_VALUE);      

// -2147483648  [10000000 00000000 00000000 00000000]
System.out.println(Integer.MIN_VALUE);

// -2147483647        
System.out.println(-Integer.MAX_VALUE);     

// -2147483648  2147483648,    ,    
System.out.println(-Integer.MIN_VALUE);     

// true,2147483648     
//                  ,     ,             
System.out.println((Integer.MIN_VALUE == -Integer.MIN_VALUE));  

この特徴は、大数オーバーフロー判定を行う際に用いられるものであり、例えばJKDソースコードにおける文字列がintタイプに変換される関数であり、Integer.parseInt(String str)では、上限に対して逆Integer.MAX_VALUEを負の数として累減するのみであり、下限に対して逆Integer.MIN_VALUEを正数として累加することはできない.
Integer.parseInt(String str)ソース:
public static int parseInt(String s) throws NumberFormatException {
      return parseInt(s,10);
}

// radix     
public static int parseInt(String s, int radix)
                throws NumberFormatException
    {
        /*
         * WARNING: This method may be invoked early during VM initialization
         * before IntegerCache is initialized. Care must be taken to not use
         * the valueOf method.
         */

        if (s == null) {
            throw new NumberFormatException("null");
        }

        if (radix < Character.MIN_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " less than Character.MIN_RADIX");
        }

        if (radix > Character.MAX_RADIX) {
            throw new NumberFormatException("radix " + radix +
                                            " greater than Character.MAX_RADIX");
        }

        int result = 0;
        boolean negative = false;
        int i = 0, len = s.length();
        int limit = -Integer.MAX_VALUE;  //          
        int multmin;
        int digit;

        if (len > 0) {
            char firstChar = s.charAt(0);
            if (firstChar < '0') { // Possible leading "+" or "-"
                if (firstChar == '-') {
                    negative = true;
                    limit = Integer.MIN_VALUE;
                } else if (firstChar != '+')
                    throw NumberFormatException.forInputString(s);

                if (len == 1) // Cannot have lone "+" or "-"
                    throw NumberFormatException.forInputString(s);
                i++;
            }
            multmin = limit / radix;
            while (i < len) {
                // Accumulating negatively avoids surprises near MAX_VALUE
                digit = Character.digit(s.charAt(i++),radix);
                if (digit < 0) {
                    throw NumberFormatException.forInputString(s);
                }

                //   10               
                //       ,   result*radix      
                if (result < multmin) {
                    throw NumberFormatException.forInputString(s);
                }
                result *= radix;

                // digit               ,        
                //          result-digit      
                if (result < limit + digit) {
                    throw NumberFormatException.forInputString(s);
                }

                //       
                result -= digit; 
            }
        } else {
            throw NumberFormatException.forInputString(s);
        }
        return negative ? result : -result;
    }


目次
  • マシン数と真値
  • マシン数
  • 真値
  • 原号
  • 逆符号
  • 補符号
  • なぜ元符号の逆符号化と補符号
  • を使用するのか
  • 補符号表示のオーバーフロー問題
  • 大数オーバーフロー問題
  • ディレクトリ