普段日常に使っている数字が10進数と呼ばれているもので、0〜9の10個の数字を使って色々な大きさを表しています。
1の位の数字が9へ来たとき、次の数字は10です。99なら100になります。決して9の次はAにはならないのです。
それでは2進数ならどうなのかと言えば、0と1しかありません。別にAとBでも良いのですが、計算しやすいように0と1にする決まりです。
1の次は10です。11の次は100になります。 2の累乗として位が上がっていくと覚えておけば問題ありません。( 10進数の場合は10の累乗です )
10進数を2進数へ変換します。
(例)10進数124を2進数へ変換します。
124を2で割った商を下へ書いてその横に余りを書きます。
62を2で割った商を下へ書いてその横に余りを書きます。
・
・
・
最後に1を2で割った商を下へ書いてその横に余りを書きます。
最初に割った余りがbit0(最下位ビット)の位置に来るため、余りを下から読んで
01111100(2)となります。 ★(2)は2進数、ビット(bit)は2進数の1桁を意味します。8ビットなら8桁( =1byte )になります。
bit0は2の0乗の位置( 一番右側=最下位ビット )、bit2は2の2乗の位置、bit7は2の7乗の位置で1byteの場合は最上位ビットになります。
10進数(1バイト)→2進数へ変換
2進数を10進数へ変換します。
2進数を10進数へ変換します。
前回の10進数で124を考えてみましょう。124=1×100+2×10+4×1=1×102+2×101+4×100で
各桁に10の2乗、1乗、0乗を掛けて加えます。
2進数も同じになり、各桁に2の7乗、6乗、5乗…0乗を掛けて加えます。
1がある所だけ取り出した方が速いので、26+25+24+23+22=64+32+16+8+4=124となります。
2進数を16進数へ
2進数4桁をまとめて0〜Fの数字に置き換えます。なぜ4桁なのかといえば、0000(2)〜1111(2)は10進数で0〜15の数字に該当します。
23+22+21+20=8+4+2+1=15で4桁ずつ区切ると綺麗に16個の記号に置き換えられるためです。
16進数では0〜9までの数字では記号が足りないので、A〜Fまでの6個の記号を借りてきて16進数を表します。
10進数 | 16進数 | 2進数 |
0 | 0 | 0000 |
1 | 1 | 0001 |
2 | 2 | 0010 |
3 | 3 | 0011 |
4 | 4 | 0100 |
5 | 5 | 0101 |
6 | 6 | 0110 |
7 | 7 | 0111 |
8 | 8 | 1000 |
9 | 9 | 1001 |
10 | A | 1010 |
11 | B | 1011 |
12 | C | 1100 |
13 | D | 1101 |
14 | E | 1110 |
15 | F | 1111 |
10101001(2)=A9(16)になります。
A( 10 )×16+9=169(10)です。 要するに2進数から16進数に変換して、10進数に直した方が速い気もします。
×16の意味は、1010・・・・の時点で、24されているので16を掛けます。( 桁が上がっていく毎に16の累乗です。 )
☆同じように、10進数から16進数への変換は、16で割って余りを出していきます。その余りを下から読んでいきます。
2進数の加算。
2進数の加算については各ビットに対応するビット値を加算していって、次の桁に桁上がりがあれば1を加えます。
6502ではキャリーフラグも加えるADC命令があります。(オペレーション:A+M+C→A アキュムレーターとメモリーと、その直前までのキャリーフラグを加えてアキュムレーターへ格納します。)
加える直前にキャリーフラグを0クリアしておきます。
★Aはアキュムレーター、Mはメモリーまたはリテラル(直値)データ、Cはキャリーフラグの意味です。
(例) 1001 1001(2) 153
0110 0111(2) 103
0(c)
━━━━━━
(c)0000 0000 …答えは256(1バイトで表される255を超えてますが、ビット7からビット8へのキャリー(桁上がり)がキャリーフラグへ格納されます。
このキャリーフラグを256と見立てて、次の上位バイトに加えれば良いため仮に4バイトサイズの整数を計算させる時も、次のキャリーが65536、16777216、・・と桁上がりがある毎に
加えられていく事になります。
2の補数表現。
2の補数はマイナスの数を作るのに役に立ちます。
6502は8ビットCPUなのでデータを扱える範囲も通常で0〜255までです。
1に255を加えると(キャリー有りの)0が返って来ます。結果的には1に-1を加えたように見えるので、
255を-1にしよう!というのが2の補数表現です。
同じように、2に254を加えると0になるので、254を-2に見立ててしまいます。
(例)-1を作ってみます。…0000 0001(2)(10進数で1)を各ビット反転し、1111 1110…これに1を加えて、1111 1111(2)で-1の出来上がりです。
0000 0001(2) 1に
1111 1111(2) -1を加えて
−−−−−−−−
(c)0000 0000(2) 結果は0…(c)はキャリー桁上がりです。
もうひとつ例題を見てみます
(例)127に-124を加える。-124を作るには124を反転して1を加えればいいので、0111 1100(2)を反転して1000 0011(2)
1を加えて、1000 0100(2)
0111 1111(2) 127に
1000 0100(2) -124を加えて
ーーーーーーーーーー
(c)0000 0011(2) 結果は3
アセンブラで書くと、
LDA ADRS2 ;引く数をロード
EOR #$FF ;$FFとの排他的論理和で反転
SEC ;キャリーをセットして
ADC ADRS1 ;引かれる数との加算 これで減算が出来ました。
これでは少し面倒なので引き算命令も用意されています( SBC命令 ) え〜ん!かなり前の話ですみませ〜ん。
オーバーフロー
2の補数同士(-128〜127)で加算を行った場合、2の補数表現(範囲は-128〜127)では表現出来ない範囲を超えたときに発生するオーバーフロービットについて考えます。
65C816の解説本ではbit6からbit7へのキャリーと、bit7からbit8へのキャリーとの排他的論理和でオーバーフロービットが成立すると書かれてあります。
例題を見ます。
0111 1111(2) 127に
0000 0001(2) 1を加える
ーーーーーーーーーー
1000 0000(2) 結果は-128…本当の答えは128ですが128は2の補数では表しきれないのでオーバーフローしてしまいました。
bit6からbit7( 最上位 )へのキャリー(桁上がり)はあったものの、bit7からbit8( キャリーフラグ )へはキャリーはありませんでした。
例題を見ます。
1111 1111(2) -1に
1111 1111(2) -1を加える
ーーーーーーーーーー
(c)1111 1110(2) 結果は-2。この答えはあってますのでオーバーフローは立たず・・。
bit6からbit7へのキャリーとbit7からbit8(キャリーフラグ)への桁上がりが同時に発生してますので、排他的論理和によって0(クリア)されます。
2進数の減算
2進数どうしの減算については、2の補数を加える事によって実現されます。(引く方の数値が2の補数)
6502ではSBC命令…(オペレーション:A-M-Cのボロー→A)。Cのボローはキャリーフラグの反転を表し、最初にキャリーフラグをセットしておきます。
(減算の借り(ボロー)を表します。)
(オペレーションではCのボローによって0を引く事と同じと解釈されます。)
(例) 0000 1001(2) 9
0000 0111(2) 7
━━━━━━━━
0000 1001(2) 9
1111 1000(2) 7 引く方を各ビット反転します。
1(c) SEC(セットキャリー命令で1にセットします。)
━━━━━━━━
(c)0000 0010 2 答えは2…SBC命令自体が引く方の数値を反転して引かれる方とキャリーフラグを加えたものと覚えましょう。
★オーバーフロービットは0
★a-b>=0の計算の時、C(キャリー)=1
a-b<0の計算の時、C(キャリー)=0