\( \require{cancel} \)
earth
湘南理工学舎
[戻る]
2024/10/03

 豆知識

 2進数の四則演算


(four arithmetic operations of binary number)
 --目 次--
  • ♦はじめに
  • ♦加算
  • ♦減算

  • ♦論理シフトと算術シフト
  • ♦乗算(左論理シフト)
  • ♦除算(右論理シフト)

  • ♦算術シフト
  • ♦乗算(左算術シフト)
  • ♦除算(右算術シフト)


  • はじめに


     ここでは「加算」,「ビットのシフト」「ビットの反転」のみにより 2進数の四則演算を行います。
    CPU (※1) には 四則演算のうち加算回路しかないものもあります。
    減算には補数の加算を, 乗算には左シフトを, 除算には右シフトを 用いて演算します。
    演算に「シフト」, あまり見慣れない言葉ですね, 本文で分かり易く説明します。
    これにより加算回路を搭載するだけで, シフト回路と反転回路により 四則演算が可能となります。
    OS (※2) が搭載されていないワンボードマイコンなどでは ソフトウェアの開発者が加算演算をベースにして, 四則演算のソフトウェアを独自に作る必要があります。
    ※1:コンピューター内臓の CPU (頭脳に相当する)【参照先】
    ※2:Windows, macOS, または様々な個別のOS などをさします。

    加 算 


    加算は10進と同様なので, 簡単に説明します。
    例1:「01011100b=5ch」と「00100111b=27h」の加算

    以下は2進8bitの加算演算です。
    2進数(xx…b), 16進数(xx…h)は前回学びました。 ☞【復習先】
    繰上げすると, 桁上がりします。
    \( \begin{array}{r} & 0& 1& 0& 1& 1& 1& 0& 0& =5ch \\ +& 0& 0& 1& 0& 0& 1& 1& 1& =27h \\ \hline & & \bt& \bt& \bt& \bt & \bt & & &←\sc{繰上げ} \\ & 1& 0& 0& 0& 0& 0& 1& 1& =83h \end{array} \)
    検算:
    ・上記の83hは10進では:
     \(83h=8\x 16+2+1=\ul{131}\)
    ・10進に変換した後の加算結果:
     \( \begin{array}{r} & 5ch &=5\x 16+12 &=92 \\ + & 27h &=2\x16+7 &=39\\ \hline &&& \ul{131} \end{array} \)

    例2:キャリー \(\sc{\boxed{1}}\) が生じる例

    \( \begin{array}{r} & 1& 1& 1& 0& 1& 0& 0& 1& =e9h \\ +& 0& 1& 1& 0& 1& 1& 0& 1& =6dh \\ \hline & \bt& \bt& \bt& & \bt & & & \bt& ←\sc{繰上げ} \\ \boxed{1} & 0& 1& 0& 1& 0& 1& 1& 0& =\boxed{1}56h \end{array} \)
    \(\boxed{1}\)は桁のあふれをしめすキャリー (またはキャリーフラグ)です。

    減 算


    減算操作をしないで, 補数の足し算に変えて,減算の結果を得ます。
    補数とは次の桁に繰り上がるための(補う)数。
    ・引く数(減数)を補数に変換します。
    例:\(\s{\ul{120-37=83}}\) を補数による減算を行います。
    補数による減算操作:
    37の10の補数は「100-37」より63です。
    (37+63=100)
    次式「被減算120に補数63を加算する」⇒減算操作です。
    \(\ul{120+\bv{63}=\boxed{1}83}\)
    \(\boxed{1}\)を無視して回答83を得る
    理解用に式を分解してみる
    \(120+(\bv{100-37})\)\(=120-37+100=83+100\)
    しかし補数を得るのに減算を使いのでは…疑問ですね!
    大丈夫です… 2進の "2の補数" は反転と加算のみでs得られます。
    …コンピューターでは反転と加算は高速で機能します。
    2進の補数は「各ビットの反転した後、1を加算」で得られます。

    例:次の減算を求める

    \(\small{A-B=0111\ 1000-\ul{0010\ 0101}}\)
    \(\small{A=0111\ 1000b=78h=120}\)

    \(\small{B=\ul{0010\ 0101}b=25h=37}\)
    \(\small{B} \sc{の反転}\) \(\ \sc{=\ \overline{ B }}\ \ \) \(\small{=\ 1101\ 1010}\)
    \(\small{B} \sc{の補数}\) \(\ \sc{=\overline{ B }}\)\(\small{+1=1101\ 1011}\)
    \( \begin{array}{r} & 0& 1& 1& 1& 1& 0& 0& 0& A \\ +& 1& 1& 0& 1& 1& 0& 1& 1& \sc{B補数} \\ \hline \boxed{1} & 0& 1& 0& 1& 0& 0& 1& 1& \sc{=\boxed{1}53h} \end{array} \)
    答えは53h(83)です。(キャリーの\(\boxed{1}\)は無視)
    検算
    ・上記の結果(補数による減算)
    \(\quad 53h=16\x 5+3=\ul{83}\)
    ・通常の減算
    \(\quad 120-37=\ul{83}\)

    論理シフト と 算術シフト


    シフト演算には次の2通りあります。
    \(\begin{cases} 論理シフト & 正負の符号を考慮せず \\ 算術シフト & 正負の符号を考慮する \end{cases}\)
    まずは基本である 論理シフト の理解を深めていきましょう。
    先に進む前に 10進数 で考えてみよう!
    (無意識にシフト演算しています)
    左シフトでは\(10\)倍, 右シフトでは\(10^{-1}=0.1\)倍です。…何故か
    その答えは次を見れば分かります。
    例: 125 をシフトする
  • ⋄左シフト:1250 ← 125
  • ⋄右シフト:125 12.5

  • 下の図をゆっくり見て先に進んでください。
    2進演算
    ・左シフト \(\s{1250 \Leftarrow \ul{125←0} }\)
    各桁を左にずらす… 上の桁に移動する
    1の桁に0が入る,5は10桁に移動,…100は千の桁に移動。
    ・右シフト \(\s{\ul{0→125} \Rightarrow 012.5=12.5}\)
    各桁を右にずらす… 下の桁に移動する。
    100の桁に0が入る,1は10桁に移動,…5は0.1の桁に移動。
    以上から次のことが言えます:
    10進数の基数10の乗除算は:
    ・\(10^n\)倍…掛け算=n回 左シフト
    ・\(10^{-n}\)倍…割り算=n回 右シフト
    2進数の基数2の乗除算は:
    ・\(2^n\)倍…掛け算=n回 左シフト
    ・\(2^{-n}\)倍…割り算=n回 右シフト

    乗 算

    (左論理シフト)
    2進数の乗算はビットの左シフトを使い, 左シフト1回で2倍 , 2回で4倍, …n回で\(\ul{2^n}\)倍となります。
    まず,右の最下位の1桁目に0 が入り, 1桁目は2桁目に移動, 2桁目3桁目に移動,…と移動する。
    これをシフトの言葉を使い表すと:
    シフトは全ビットが左へ移動し, 最下位ビット(LSB)(右)に 0 が入り,最上位ビット(MSB)(左)から押し出されたものは捨てられる。(※1,※2)
    4ビットを例にすると:
    シフトは 1, 2, 3回で \(\ul{\s{1\x 2=2}}\)倍 → \(\ul{\s{2\x 2=4}}\)倍 → \(\ul{\s{4\x 2=8}}\)倍 の乗算となります。(元の数に対して2倍,4倍,8倍)
    ※1:※2:この例では:
    最下位ビット(\(2^0の桁\))をLSB(Least significant bit) という。
    最上位ビット(\(2^3の桁\))をMSB (Most significant bit) という。

    [4bitの左シフト]
    \( \begin{array}{ccccc|cccc|ccC} & && & & \sc{2^3}& \sc{2^2}& \sc{2^1}& \sc{2^0}& & &\\ \sc{左シフト}& && & ← & 0& 0& 0& 1& ←& &\\ \hline \sc{1回=\x 2}& & & & 0\sc{←}& 0& 0& 1& 0& \sc{←}0& &\\ \sc{2回=\x 4}& & & 0& 0\sc{←}& 0& 1& 0& 0& \sc{←}0& 0&\\ \sc{3回=\x 8}& & 0& 0& 0\sc{←}& 1& 0& 0& 0& \sc{←}0& 0& 0\\ \sc{4回=\x 0}& 0& 0& 0& \sc{\bx{1}←}& 0& 0& 0& 0& \sc{←}0& 0& 0&0 \end{array} \)
    4回シフトではMSBの"1" が押し出されています, これをキャリーフラグといいます。
    キャリーフラグを捨てるか否かプログラムによる。

    例:2進8bitの"0010 0111"を4倍,8倍する


    題記の 2進 → 16進 →10進 変換すると:
    "0010 0111"=27h \(=2\x 16+7\)=39
    答えは⇒4倍は 156 , 8倍は312 です。
    [8bit数値の左シフト]
    \( \begin{array}{c|ccc|cccccccc|ccc} & & & & \sc{2^7}&\sc{2^6}&\sc{2^5}&\sc{2^4}&\sc{2^3}&\sc{2^2}&\sc{2^1}&\sc{2^0}& & & &\\ & & & & 0& 0& 1& 0& 0& 1& 1& 1& & & &\\ \hline \x 4=& & 0& 0\sc{←}& 1& 0& 0& 1& 1& 1& 0& 0& \sc{←}0& 0& &\\ \x 8=& 0& 0& \sc{\bx{1}←}& 0& 0& 1& 1& 1& 0& 0& 0& \sc{←}0& 0& 0&\\ \end{array} \)
    4倍(\(2^2\))は左シフトを2回:
    ・1001 1100=9ch=\(\sc{9\x 16+12}\)=156
    8倍(\(2^3\))は左シフトを3回:
    ・0011 1000=38ch=\(\sc{3\x 16+8}\)=56(不正解)
    オーバーフロー発生が発生,結果はエラーである。
    しかし, オーバーフローを考慮し, 9ビットデータにとすると:
    ・1 0011 1000=138ch=\(\sc{256\x 1 +3\x 16+8}\)=312

    除 算

    (右論理シフト)
     除算はビットの右シフトを使い, 右シフト1回で\(\frac{1}{2}\)倍 , 2回で\(\frac{1}{4}\)倍, … n回で\(\frac{1}{2^n}\)倍 となります。
    右シフトする度に2の乗数が"-1, -2, -3, … -n" 変化します。
    \(2^{-1}=\frac{1}{2^1}=\frac{1}{2}=0.5\)
    \(2^{-2}=\frac{1}{2^2}=\frac{1}{4}=0.25\)
    \(2^{-3}=\frac{1}{2^3}=\frac{1}{8}=0.125\)
    \(\qquad \vdots\)
    \(2^{-n}=\frac{1}{2^n}\)
    シフトは全ビットが右へ移動し, 最上位ビット(MSB)(左)に 0 が入り,最下位ビット(LSB)(右)から押し出されたものは捨てられる
    4ビットを例すると:
    シフトは 1, 2, 3回で \(\ul{\frac{1}{2}}\) → \(\ul{\frac{1}{4}}\) → \(\ul{\frac{1}{8}}\) の除算となります。
    元の数に対して\(\frac{1}{2}\)倍,\(\frac{1}{4}\)倍,\(\frac{1}{8}\)倍になります。
    \( \begin{array}{ccccc|cccc|ccc} & && & & \sc{2^3}& \sc{2^2}& \sc{2^1}& \sc{2^0}& & &\\ \sc{左シフト}& && & →& 1& 0& 0& 0& →& &\\ \hline \sc{1回=2}& & & & 0\sc{→}& 0& 1& 0& 0& \sc{→}0& &\\ \sc{2回=4}& & & 0& 0\sc{→}& 0& 0& 1& 0& \sc{→}0& 0&\\ \sc{3回=8}& & 0& 0& 0\sc{→}& 0& 0& 0& 1& \sc{→}0& 0& 0\\ \sc{4回=0}& 0& 0& 0& 0\sc{→}& 0& 0& 0& 0& \sc{→\bx{1}}& 0& 0& 0& \end{array} \)
    4回シフトではMSBの"1" が押し出されています, これをキャリーフラグといいます。
    例: "0100 0101"(69)を4で割る。


    "0100 0101"=45h \(=4\x 16+5\)=69
    \(69÷4=17…余り1\)
    小数を扱っていないから余りがでる。
    "0100 0101" を右シフトを2回(÷4)すると以下になります。
    \( \begin{array}{c|cc|cccccccc|cc} & & & \sc{2^7}&\sc{2^6}&\sc{2^5}&\sc{2^4}&\sc{2^3}&\sc{2^2}&\sc{2^1}&\sc{2^0}& & & \\ & & & 0& 1& 0& 0& 0& 1& 0& 1& 0& 0& \\ \hline \s{÷4=} & 0& 0\sc{→}& 0& 0& 0& 1& 0& 0& 0& 1& \sc{→}0& ①& \\ \end{array} \)
    0001 0001=11h=\(\sc{1\x 16+1}\)=17…余り1 (押し出された ① は余りです)

    小数のシフト演算

    (右/左 論理シフト)
    ここで 小数を含む2進数のシフトをはどうなるか:
    次の例で学ぼう!
    例.次は 小数 の2進数を左右にシフトします。
    "0 1100.110"=0c.5h=12.75
    整数5ビット+小数は3ビットです。
    \( \begin{array}{c|cc|ccccccccc|cc} & & & \sc{2^4}&\sc{2^3}&\sc{2^2}&\sc{2^1}& \sc{2^0}& .& \sc{2^{-1}}& \sc{2^{-2}}& \sc{2^{-3}}& & & \\ & & & 0& 1& 1& 0& 0& .& 1& 1& 0& 0& & \\ \hline \s{÷2=} & & 0\sc{→}& 0& 0& 1& 1& 0& .& 0& 1& 1& \sc{→}0& & \\ \hline \s{\x 2=} & & 0\sc{←}& 1& 1& 0& 0& 1& .& 1& 0& 0& 0\sc{←}& & \\ \end{array} \)
    \(\ul{\s{÷2=}}\):右シフト
    10進計算では\(12.75÷2=\ul{6.375}\)
    シフト演算では上記より \(4+2+0.25 +0.125=\ul{6.375}\)
    \(\ul{\s{\x 2=}}\):左シフト
    10進計算では\(12.75\x 2=\ul{25.5}\)
    シフト演算では上記より \(16+8+1+0.5=\ul{25.5}\)
    注:桁あふれのとき論理シフト(符号なし演算)ではキャリーフラグが, 次に学ぶ算術シフト(符号付き演算)ではオーバーフローフラグが機能します。(当然このフラグの使い方を決めるのはソフトです)

    算術シフト


     2進数では「符号なし」と「符号つき」は予め決めておく内容です。
    算術シフトは「符号つき」2進数の操作です。
    2進数8bitデータとすると「符号つき2進数」は先頭ビットを正負の符号ビット, 負数は「2の補数」を使います。
    従い表せる数は符号なしの「256」 に対し 符号付きは「-128~0~+127」です。
    以下は算術シフトをまとめた内容です。
    符号ビット(0:正, 1:負)はシフトに対し固定(不動)です。
    符号ビットは最上位におき, シフトには寄与しません。
    •負数(符号ビット=1)のとき数値データは 2の補数表記です。
    ここでは負数のシフト演算について説明します。
    正数の算術シフトは符号ビット(0)を固定する以外は論理シフトと同じなので省略します。
    •符号無2進数と符号付2進数の表現範囲
    \( \begin{array}{|c|c|c|} \hline 2進数 & \s{符号付2進数} & \s{符号付2進数}\\ & \s{(10進表示)} & \s{(10進表示)}\\ \hline 0000\ 0000 & 0 & 0 \\ 0000\ 0001 & 1 & 1 \\ 0000\ 0010 & 2 & 2 \\ \vdots & \vdots & \vdots\\ 0111\ 1111 & 127 & 127\\ \hline 1000\ 0000 & 128 & -128\\ 1000\ 0001 & 129 & -127\\ \vdots & \vdots & \vdots\\ 1111\ 1110 & 254 & -2 \\ 1111\ 1111 & 255 & -1 \\ \hline \end{array} \)

    ここから先は負数のシフト演算です。

     乗 算 

    (左算術シフト)
    最上位に符号ビット "1", 左シフトでは最下位に"0" が入ります。
    また上位から追い出される数が符号ビットと異る数値 "0" のときはオーバーフローです。

    例:10進の負数 "-39" を2倍, 4倍してみよう。

    まず, 39d="0010 0111"を負数(2の補数) に変換します。
    ・先頭ビット\(\Rightarrow\) " \(\boxed{1}\) ":符号ビット(負)は固定です。
    符号ビットを除き "2の補数" に変換する。
    ・ビット反転\(\Rightarrow\) "\(\ \boxed{1}\ \ul{101\ 1000}\)"
    ・上記 + 1 \(\Rightarrow\) "\(\ \boxed{1}\ 101\ 100\ul{1}\)"
    \(\therefore\) -39d="\(\ul{ \boxed{1} 101 1001 }\)"

    10進で予め計算してみると:
    -39\(\x\)2=-156㋐  -39\(\x\)4=-156㋑
    (-312はオーバーフローしますね)

    左算術シフトは以下の通り:
    \( \begin{array}{c|ccc|cccccccc|ccc} & & & & \sc{2^7}&\sc{2^6}&\sc{2^5}&\sc{2^4}&\sc{2^3}&\sc{2^2}&\sc{2^1}&\sc{2^0}& & & &\\ & & & & \bx{1}& 1& 0& 1& 1& 0& 0& 1& & & &\\ \hline \x 2= & & & 1\sc{←}& \bx{1}& 0& 1& 1& 0& 0& 1& 0& \sc{←}0& & &\\ \x 4= & & \ul{\cl{0}}& 1\sc{←}& \bx{1}& 1& 1& 0& 0& 1& 0& 0& \sc{←}0& 0& &\\ \end{array} \)
    注: [\( \x 4=\)] の \(\ul{\cl{0}}\) (※) はオーバフローを意味します。
     (※)符号ビットと異なる数のときオーバフローとなる。

    検算:
    以下 "負の符号ビット" は省略し,7ビットで評価。
    1. \(\ul{÷2:}\) 結果の "\(\ 101\ 1110\)" を2の補数に変換"\(\ 0 1 0 \ 0 0 1 0\)"
    =22h=32+2=34(負)\(\Rightarrow\)正解

    2. \(\ul{\x 4:}\) 結果の "\(\ 1 1 0\ 0 1 0 0\)" を2の補数に変換"\(\ 0 0 1\ 1 1 0 0\)"
    \(=1c\ h\)=16+12=28 \(\rightarrow\)オーバーフロー発生
    オーバーフローのビットは\(2^7=128\)の桁を足せば\(\rightarrow\) 156(負) (正解になる)

    3.オーバーフローの扱いはソフトウェアによります。

    除 算

    (右算術シフト)
    最上位に符号ビット "1", 右シフトで空くスペースには"1" (符号ビットと同じ)が入る。 (正の数の場合は"0"が入る)
    下位から追い出される数は無視するが、数値が"1" のときは余りを示します。
    例1: "1011 1100"(-68)を2で割る。


    上記は"0100 0100"(68)の2補数表記です。
    \( \begin{array}{c|cc|cccccccc|cc} & & & \sc{2^7}&\sc{2^6}&\sc{2^5}&\sc{2^4}&\sc{2^3}&\sc{2^2}&\sc{2^1}&\sc{2^0}& & & \\ & & & \bx{1}& 0& 1& 1& 1& 1& 0& 0& & & \\ \hline \s{÷2=} & & 1\sc{→}& \bx{1}& 1& 0& 1& 1& 1& 1& 0& \sc{→}0& & \\ \end{array} \)
    検算:
    以下符号ビットは省略し,7ビットで評価。
    \(\ul{÷2:}\) 結果の "\(101 1110\)" を2の補数に変換した "\(010 0010\)"
    =22h=32+2=34\(\Rightarrow\)正解

    例2: "1011 1011"(-69)を2で割る

    余りが出る例
    上記は"0100 0101"(69)の2補数表記です。
    \( \begin{array}{c|cc|cccccccc|cc} & & & \sc{2^7}&\sc{2^6}&\sc{2^5}&\sc{2^4}&\sc{2^3}&\sc{2^2}&\sc{2^1}&\sc{2^0}& & & \\ & & & \bx{1}& 0& 1& 1& 1& 1& 0& 1& & & \\ \hline \s{÷2=} & & 1\sc{→}& \bx{1}& 1& 0& 1& 1& 1& 1& 0& \sc{→} ① & & \\ \end{array} \)
    検算:
    結果は前の例1 と同じ正解。
    異なるのは, 右にはみ出た「①」 がある, すなわち「余り…1」を示している。

    …以上
      

    coffe
    [コーヒーブレイク/閑話]…お疲れさまでした