8ビットの符号付き整数で −8(1111 1000)を算術右シフトで1ビット右にずらした結果はどれか。
- A124(0111 1100)
- B−16(1111 0000)
- C−4(1111 1100)
数値と入力の基数、ビット幅を選ぶと、2進数・8進数・10進数・16進数での表し方をまとめて示します。負の数は2の補数で表し、同じビット列を符号なしで読んだ値と符号つきで読んだ値、表せる範囲、全ビットの反転と符号の反転も表示します。基本情報技術者試験などで扱われる数値表現の計算を、手で解いたあとに確かめるのにも使えます。
入力した条件はこのページのURLに入るので、ブックマークや共有をすると同じ計算結果を開けます。お気に入りと最近使ったツールは、このブラウザ内(localStorage)にのみ保存されます。
負の数は選んだビット幅の2の補数で表し、入力中の空白と _ は無視します。
ほかの入力は今の値のまま、選んだ入力だけを今の値の1/4〜4倍の範囲で変えたときの結果です。赤い点が今の値です。
10進数を2進数にするには、2で割った余りを下の桁から順に並べます。逆に2進数を10進数にするには、各桁に1、2、4、8…の重みを掛けて足します。16は2の4乗なので、2進数を下位から4桁ずつ区切ると、それぞれが16進数の1桁(0〜9とA〜F)に対応します。8進数は同じように3桁ずつです。既定値の−5を8ビットで表すと1111 1011で、1111がF、1011がBなので16進数では0xFB、符号なしの10進数では128 + 64 + 32 + 16 + 8 + 2 + 1 = 251です。3桁ずつ011 111 011と区切ると、8進数では373になります。このツールは2進数と16進数を4桁ごとに区切って表示するので、両者の対応を目で確かめられます。
nビットの2の補数では、負の数 −x を 2ⁿ − x というビット列で表します。全ビットを反転した値(1の補数)は (2ⁿ − 1) − x なので、それに1を足すとちょうど 2ⁿ − x になります。これが「反転して1を足す」と符号が逆になる理由です。8ビットの5は0000 0101で、反転すると1111 1010、1を足すと1111 1011となり、256 − 5 = 251と一致します。2ⁿで割った余りで計算する加算器では、2ⁿ − x を足すことと x を引くことが同じ結果になるので、減算も加算器で行え、符号なしと符号つきの数を同じ回路で扱えます。ツールの「符号の反転」では、既定値の−5(1111 1011)を反転した0000 0100と、1を足した0000 0101(+5)が表示されます。
nビットの符号なし整数は0〜2ⁿ − 1、2の補数の符号つき整数は −2ⁿ⁻¹〜2ⁿ⁻¹ − 1を表せます。8ビットでは0〜255と−128〜127、16ビットでは0〜65535と−32768〜32767、32ビットでは0〜4294967295と−2147483648〜2147483647です。最上位ビットが0の側に0が含まれるので、正の数は負の数より1つ少なくなります。そのため、最小の負の数は符号を反転できません。8ビットで−128(1000 0000)を入れると、反転して0111 1111、1を足して1000 0000となり、−128のまま戻ることをツールで確かめられます。プログラムで最小値の絶対値をとったり −1 を掛けたりするとオーバーフローするのは、この非対称のためです。
ビット列そのものは符号の情報を持たず、符号なしとして読むか2の補数として読むかで値が変わります。最上位ビットが0なら両者は等しく、1なら符号つきの値は符号なしの値から2ⁿを引いたものです。1111 1011は符号なしで251、符号つきで251 − 256 = −5です。符号つきの数のビット幅を広げるときは、最上位ビットを上位の桁すべてにコピーします(符号拡張)。−5は16ビットでFFFB、32ビットでFFFF FFFB(16進数)となり、値は−5のままです。上位を0で埋めるゼロ拡張では、00FBとなって251になります。ツールで10進数の−5のままビット幅を変えると符号拡張の結果が、16進数でFBと入れてビット幅を変えるとゼロ拡張の結果が見られます。
nビットの加算では、結果は2ⁿで割った余りになり、収まらない上位の桁は捨てられます。符号なしの加算では最上位ビットから外へ桁上げ(キャリー)が出たとき、符号つきの加算では正の数どうしの和が負に、負の数どうしの和が正になったときが桁あふれ(オーバーフロー)です。8ビットで127 + 1の結果にあたる128をツールに入れると、ビット列は1000 0000で、符号なしでは128ですが符号つきでは−128と読まれます。10進数の−1を32ビットで入れると符号なしでは4294967295となり、C言語の符号なし整数で0 − 1を計算した結果と一致します。基本情報技術者試験の基礎理論では、基数変換、2の補数による負の数、nビットで表せる範囲、シフト演算などの計算が扱われます。このツールは範囲を超えた値を入れると下位のビットだけを残して警告を出すので、レジスタの中で何が起きるかを確かめられます。
正解:B. 4294967295
符号なし整数には負の数がなく、C言語では結果を 2³² で割った余りとして扱う(回り込む)と定められています。0 − 1 は 2³² − 1 = 4294967295 になり、ビット列はすべて1です。このため、「i が0になるまで1ずつ減らす」ループを符号なしの変数で i >= 0 と書くと、条件が常に真になって終わらなくなります。符号なしでは −1 は表せず、0のまま止まる(飽和する)わけでもありません。
正解:C. 最上位のビットから外へ桁上げが出たかどうかを見る
符号なしの足し算では、最上位のビットからさらに上へ桁上げが出たとき、結果がビット数で表せる最大値を超えています。CPUではこの桁上げがキャリーフラグとして残るので、それを調べれば判定できます。結果の最上位ビットが1になるのは、単に大きな数になっただけで桁あふれではありません。最上位ビットへの桁上げと最上位ビットからの桁上げの違いを見るのは、符号付きの数のオーバーフローの判定方法です。
5を8ビットで書くと0000 0101です。全ビットを反転して1111 1010、1を足して1111 1011になり、16進数では0xFB、符号なしとして読むと251です。256 − 5 = 251と計算しても同じビット列が得られます。
下位から4桁ずつ区切り、それぞれを0〜9、A〜Fの1桁に置き換えます。たとえば1011 0110は、1011がB、0110が6なのでB6です。桁数が4の倍数でないときは、上位に0を補ってから区切ります。8進数に変換するときは3桁ずつ区切ります。
8ビットの256通りのうち、最上位ビットが1の128通りが負の数(−128〜−1)に、0の128通りが0と正の数(0〜127)に割り当てられるからです。0が正の側の1つを使うため、+128は表せません。一般にnビットでは −2ⁿ⁻¹〜2ⁿ⁻¹ − 1 です。
1の補数は全ビットを反転しただけの表現で、+0(0000 0000)と−0(1111 1111)の2つのゼロができ、加算では最上位からの桁上げを最下位に足し戻す処理(循環桁上げ)が必要です。2の補数は反転してさらに1を足した表現で、ゼロは1つだけになり、符号なしと同じ加算器で計算できます。そのため、現在の一般的なコンピュータは整数に2の補数を使っています。
8ビットでは、符号なしで255、2の補数の符号つきで−1です。同じFFでも16ビットで入れると00FFとなり、符号つきでも255です。値がいくつになるかは、ビット幅と、符号つきとして読むかどうかで決まります。