小数

前章の負の数に続き,今度は実数(小数部のある数)の扱いについて考える。 当然だが,小数部のある数も,何らかの 0 と 1 の並びで表す必要があり,それに対する加減乗除も行えなければならない。 小数部のある数の表現の仕方,及び加減乗除の方法について見ていこう。

2進法の小数

多くのコンピュータでは,実数も2進法で表して記憶・演算を行っている。 まずは2進法の小数について理解しよう。

10進法では,右の桁は左の桁の 10分の1 の重みを持つものとして扱う。同様に,2進法では,右の桁は左の桁の ½ の重みを持つものとして扱う。 例えば2進数 0.101 は,小数点の右は ½ の桁,その右は ¼ の桁,その右は ⅛ の桁,… となるので,10進法では 0.625 (= ½ + ⅛) だ。

ソースコードに 0.625 と書いていても,コンピュータがその数をレジスタに代入したり演算に使ったりするときは2進数 0.101 の形で(ただし,後述の方法で小数点のない形にして)扱うわけだ。

補足: 小数の基数変換

0以上1未満の小数について,1桁ずつ値を取り出す方法を考えよう。

まず10進数で考える。 x = 0.375 という10進数を考えると,小数第1位 (= 3) は「x を10倍すると1の位になる数」,小数第2位 (= 7) は「x を100倍すると1の位になる数」,小数第3位 (= 5) は「x を1000倍すると1の位になる数」だ。

同じことが2進数でも言える。 x = 0.011 という2進数を考えると,小数第1位は「x を2倍すると1の位になる数」,小数第2位は「x を4倍すると1の位になる数」,小数第3位は「x を8倍すると1の位になる数」だ。

このことを使うと,2進法の小数を10進表記に変換したり,10進法の小数を2進表記に変換したりできる。 前者は「10倍して整数部を取り出す」ことを繰り返せばよく,後者は「2倍して整数部を取り出す」ことを繰り返せばよい。

例えば10進数 0.375 を2進表記に変換したい場合:

0.375 × 2 = 0.75 → 小数第1位は 0, 余り 0.75
0.75  × 2 = 1.5  → 小数第2位は 1, 余り 0.5
0.5   × 2 = 1    → 小数第3位は 1, 余り 0

答えは 0.011。

2進数 0.011 を10進数に変換したい場合(区別のため,10進数には末尾に d を付けている):

               2倍 + 8倍
0.011 × 10d = 0.11 + 11 = 11.11 → 小数第1位は 3d, 余り 0.11
0.11  × 10d = 1.1 + 110 = 111.1 → 小数第2位は 7d, 余り 0.1
0.1   × 10d = 1  +  100 = 101   → 小数第3位は 5d, 余り 0

答えは 0.375。

問: 10進数 0.1 は2進法ではどう表されるか?

問: 2進法で有限小数で表せる数は10進法でも有限小数となるか? 逆に,10進法で有限小数で表せる数は2進法でも有限小数となるか?
(参考:基本情報技術者試験 H20秋 午前問2)

小数同士の乗算,加算

小数部のある数の積を人手で計算する場合,どのような手順で行っているだろう? まずは小数点を無視して積を計算し,その後で小数点の位置を決めているはずだ。 例えば10進法で 1.25 × 3.5 を計算する場合,まず小数点を無視して 125 × 35 = 4375 を計算した後,下から3桁目に小数点を付けて 4.375 を結果とする。被演算数の小数部の桁数が 2 と 1 なので,結果の小数部の桁数は 3 となる。

          小数点を無視して計算
  1.25       125
x) 3.5  →  x) 35
-------    ------
             625
            375
           ------
            4375   → 4.375 小数部の桁数に応じて小数点を付ける

つまり,小数部の桁数を別途覚えておけば,小数同士の乗算は整数同士の乗算と同じだ。

これは2進法でも同じことだ。 被演算数を整数と見なして乗算を行い,最後に小数点の位置を調節すればよい。 例えば2進法で 1.01 × 11.1 を計算する場合,まず 101 × 111 = 100011 を計算した後,下から3桁目に小数点を付けて 100.011 を結果とする(10進法での計算結果 4.375 と一致している)。

加算は以下のように行う。

加算は,小数点位置を揃えてから行う。
 10進法          2進法
   1.25            1.01
+) 3.5         +) 11.1
--------       ---------
   4.75          100.11

加算の場合は,被演算数の小数部の桁数が揃うように先にシフトを行ってから,整数と同じように加算すればよい。 2進法で 1.01 + 11.1 を計算する場合,小数部の桁数を2桁に揃えて 1.01 + 11.10 とした後,小数点を無視して加算を行えばよい(101 + 1110 = 10011)。和の小数部の桁数は,加算前の被演算数と同じ2桁だ。つまり,結果は 100.11,10進法では 4.75 (= 1.25 + 3.5) だ。

固定小数点数

「整数部8ビット,小数部24ビット」のように,予め小数部の桁数を決めて小数を扱うことを,固定小数点演算 (fixed-point arithmetic) と言う。 整数部 n ビット,小数部 m ビットで表された数を「n.m 形式の固定小数点数」と言う。

例えば,10進数 1.25 と 3.5 を8.8形式で表すと,それぞれ 0x0140, 0x0380 になる。

00000001.01000000 (= 0x0140)
00000011.10000000 (= 0x0380)

1.25 や 3.5 の代わりに 1.25 × 28 (= 320) や 3.5 × 28 (= 896) をレジスタに格納する,と考えてもよい。

四則演算は整数と同じように行う。 例えば,上記の2つの数がAXとBXに格納されているとき,mul bx を実行すると,結果は32ビットの数 0x00046000 になるが,これは16.16形式で表された積 4.375 と等しい (28倍された2数を乗じたので,結果の216倍が得られる)。 n.m 形式の数と n'.m' 形式の数を乗算すると,結果は (n + n').(m + m') 形式の数になる。 もし 8.8 形式の結果が必要なら,一度 16.16 形式の積を求めた後,シフト命令等を使って小数部の桁数を調節する。

固定小数点演算では,コンピュータは小数点を管理しておらず,単に整数演算を行っているだけであることに注意。 各レジスタに何形式の数が格納されているかはプログラム作成者(またはコンパイラ)が把握しておき,小数点以下の桁数を変更したい場合はシフト命令等を挟む必要がある。

参考: 浮動小数点数

例えば 6.02 × 1023 や 6.67 × 10−11 のような表記(科学的表記)では,1023 や 10−11 が小数点の位置を表している。 これと同じように,有効数字を表す部分(仮数)と小数点の位置(指数)の組で一つの小数を表して扱うことを,浮動小数点演算 (floating-point arithmetic) と言う。 つまり,表したい小数が 1.xxx × 2e であるときに,xxx と e(共に2進数)を並べたビット列をレジスタや主記憶に格納する。

IEEE 754という標準規格に従って32ビットで小数を表す場合,符号に1ビット,指数に8ビット,仮数に23ビットを使う。 例えば,10進数 13.375 は2進数では 1101.011 = 1.101011 × 23 なので,浮動小数点数で表す場合は仮数 1.101011 と指数 3 の組を32ビットの中に詰めて表す(具体的な詰め方は各自調べなさい)。

C言語やJavaのfloat型・double型は浮動小数点数を意味する型であり,これらの型の演算は,必ず浮動小数点演算を行う機械語プログラムに翻訳しなければならない。

浮動小数点数の四則演算は,仮数同士,指数同士をそれぞれ演算することで行う。 例えば乗算は,仮数同士を掛け,指数同士を足せばよい。 シフト命令と論理演算で仮数と指数を取り出して,それぞれMULやADD命令で演算して,また32ビットの中に詰め直して,… とプログラムすれば実現できるが,通常は,CPUに内蔵されている浮動小数点演算器 (floating-point number processing unit; FPU) を使う。 パソコン用やそれ以上の規模のCPUはFPUを内蔵している場合が多い。 現在市販されているi386アーキテクチャのCPUもFPUを内蔵しているが,レジスタも命令もFPU独特のものを使うようになっている。

補足: 負の小数

負数を扱う場合,固定小数点数では2の補数を使うことが多い。 例えば 8.8 形式で −1.25 を表す場合,1.25 を表すビット列 0x0140 の2の補数である 0xfec0 を使う。 これは,−1.25 × 28 = −320 を16ビットで表した場合と一致する。 つまり,「8.8形式では,数 x を,x × 28 である整数で表す」という考えと整合している。

  • 参考: 浮動小数点数の標準規格であるIEEE 754では,負数は符号ビットと絶対値で表す。 例えば −1.25 は,1.25 を表すビット列の符号ビットを1に変えたもので表す。

results matching ""

    No results matching ""