空きが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バイトで表す
| けたの重み | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|---|---|---|
| ビット | 1 | 0 | 1 | 0 | 1 | 1 | 0 | 0 |
| 足す値 | 128 | 0 | 32 | 0 | 8 | 4 | 0 | 0 |
学生が入力するセルは、このプレビューでは空白です。
アーキテクチャのフォルダへ移る
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の補数で読む |
|---|---|---|
| 00000100 | 4 | 4 |
| 01111111 | 127 | 127 |
| 10000000 | 128 | -128 |
| 11111100 | 252 | -4 |
| 11111111 | 255 | -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ビットのレジスタに読み込むとき、プロセッサが何をすべきかを説明してください。