クリーム色の背景、色付き表示、高コントラスト、大きな文字のほうが読みやすいですか?配色と文字を選ぶと、すべてのページに一度で反映されます。

無料レッスン

数と文字をビットで表す(2の補数)

このレッスンのあとで: 数と文字を、ビットの並びとして表すことができる。

55分のレッスンコマンド11件コンパイラとアーキテクチャのラボ:gcc、flex、bison、RISC-V を1台の VM で

空きが252台の駐車場

駅前の駐車場の看板が、ある朝「空き252台」と表示しました。この駐車場は、全部で40台しか止められません。

原因は、満車のときに空きの数から4を引いてしまったことでした。答えの -4 は、8ビットの中にしか入りません。看板はその8ビットを、ふつうの正の数として読みました。今日は、この「読み方」の話をします。

このレッスンのゴール

メモ

数と文字を、ビットの並びとして表すことができる。

キーワード

ことばいみれい
ビット0か1の、1けたの値
バイト8ビットのまとまり。メモリはこの単位で数える
2進数0と1だけで数を書く方法10101100
16進数16で1けた上がる書き方。1けたが4ビットにあたる0xac
2の補数負の整数をビットで表す、ふつうのやり方
文字コード1つの文字を表す番号65 は A

学生が入力するセルは、このプレビューでは空白です。

2進数は、けたごとに2倍

ふだんの10進数では、1けた左に行くと値が10倍になります。2進数では、1けた左に行くと2倍になります。

1バイトは8けたで、けたの重みは左から 128、64、32、16、8、4、2、1 です。1が立っているけたの重みを足すと、その数になります。10101100 なら、128 + 32 + 8 + 4 で172です。

例: 172を1バイトで表す

けたの重み1286432168421
ビット10101100
足す値12803208400

学生が入力するセルは、このプレビューでは空白です。

アーキテクチャのフォルダへ移る

コマンド
cd ~/arch

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

Python で3つの変換をする

コマンド
python3 -c "print(bin(42), hex(200), int('101010', 2))"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

シェルでも16進数を出せる

コマンド
printf '%d %x\n' 300 300

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

16進数の1けたは4ビット

16進数には16個の数字があります。0から9のあとに、10から15を a から f で書きます。16進数の1けたは、ちょうど4ビットです。

だから1バイトは、いつも16進数2けたになります。172は 1010 1100 なので、a と c で 0xac です。メモリや機械語を見る道具が16進数を使うのは、短くて、ビットとも対応するからです。

負の数は、いちばん上のビットで表す

ビットの並びには、マイナス記号がありません。2の補数では、8ビットの最上位のけたの重みを 128 ではなく -128 にします。ほかの7けたは、ふつうの重みのままです。

すると 11111111 は -128 + 127 で -1 になります。負の数を書くときは、256 を足してから、ふつうの数として書きます。-4 なら 252 で、11111100 です。

例: 同じ1バイトの2つの読み方

ビット符号なしで読む2の補数で読む
0000010044
01111111127127
10000000128-128
11111100252-4
11111111255-1

学生が入力するセルは、このプレビューでは空白です。

引き算をする RISC-V のプログラムを書く

コマンド
printf '.globl _start\n_start:\n  li a0, 5\n  li a1, 9\n  sub a0, a0, a1\n  li a7, 93\n  ecall\n' > neg.s

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

アセンブルする

コマンド
riscv64-linux-gnu-as neg.s -o neg.o

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

リンクする

コマンド
riscv64-linux-gnu-ld neg.o -o neg

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

エミュレータで実行する

コマンド
qemu-riscv64 ./neg

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

終了ステータスを読む

コマンド
echo $?

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

よくある間違い

注意

「ビットを見れば、負の数かどうかが分かる」と考える人が多くいます。分かりません。プログラムは 5 - 9 を計算して、a0 に -4 を入れました。Linux は下の8ビット 11111100 だけを残し、シェルはそれを符号なしで読んで 252 と出しました。同じビットでも、読む側の決め方で意味が変わります。

文字も、数として記録される

コンピュータは、文字を文字コードという番号で記録します。A は65、a は97です。最初の128個は、よく使うどの方式でも同じです。

UTF-8 は、その128個を1バイトずつで記録します。ほかの文字は2から4バイトです。ひらがなの「あ」は番号12354で、UTF-8 では e3 81 82 の3バイトになります。だから日本語の文は、文字数よりバイト数のほうが多くなります。

「あ」のバイトと、A の番号

コマンド
python3 -c "print(chr(12354).encode('utf-8'), len(chr(12354).encode('utf-8')), ord('A'))"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

小数は、近い値で記録される

0.1 のような小数は、浮動小数点で記録します。符号、2の何乗か、そして端数を、合わせて64ビットに入れます。

ほとんどの10進の小数は、2の累乗でぴったり書けません。3分の1を10進数でぴったり書けないのと同じです。だから 0.1 を3回足しても、0.3 にとても近い別の値になります。お金や個数を浮動小数点の == で比べてはいけません。

0.1 を3倍する

コマンド
python3 -c "print(0.1 * 3)"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

2026 のバイトを、小さいほうから

コマンド
python3 -c "print((2026).to_bytes(4, 'little').hex(' '))"

ここでは表示のみで、実行されません。無料アカウントを作成すると、実行ボタンで自分のラボのターミナルに入力できます。

さらに挑戦

-37 を、まず8ビットで手で書いてください。次に16ビットで書きます。左に増えた8ビットは、どうなっていますか。

両方を、課題の to_pattern で確かめましょう。最後に、符号付きの1バイトを64ビットのレジスタに読み込むとき、プロセッサが何をすべきかを説明してください。

このラボとソースについて: コンパイラとアーキテクチャのラボ:gcc、flex、bison、RISC-V を1台の VM で

授業で使いますか?このモジュールを学生に割り当てると、教員用ガイド、自動採点つきの課題、学生ごとのラボを使えます。