浮動小数点数とその精度

◎数値の浮動小数点表現

ディジタル計算機では、原理的には整数しか表現できない。 しかし、Fortran, Pascal, Cなどの言語には、実数型というものがある。 本来の実数は、小数で表現すれば無限の桁数が必要だが、 計算機の中の実数型は、有限の桁数である。 数値計算向きのプログラム言語での実数は、 浮動小数点(「不動」ではない!!)という方式で近似表現され、 これをふつう実数型と呼んでいる。 理学・工学でよく使う、「aかける10のn乗」という表現と同様のもので、 ある底(てい、上の例では10)を使い、指数部(上の例のn)と仮数部(上の例のa) で数値を表現する。 仮数部の桁数は、数値の絶対的精度ではなく、相対精度(いいかえれば有効数字)を 保証するものである。 (数値計算以外の計算機利用では浮動小数点表現は必ずしも一般的ではない。 数式処理では有理数の分数表現、事務計算では固定小数点数を使うことが多い。)

計算機内部の数値の表現は、2進法が基本なので、 浮動小数点数の底も10でなく、 2 (機種によっては16)が使われている。

一方、数値を計算機が人間とやりとりする場 (標準入出力やテキストファイルの読み書き、プログラム中の定数など)では、 10を底とする浮動小数点表現がふつうである。 たとえば 3かける10の(-5)乗は、3.0e-5 のように表現する (この例は、固定小数点表現で 0.00003 と書いても同じ数値である)。 「e」は「指数」に対応する英語「exponent」から来ているが、 ここでは e = 2.718... (自然対数の底)とは関係なく、10のなん乗を 表わしていることに注意。

この授業で使う計算機の実数型の精度を確認してみよう。 1とたして1と区別がつく最小の正の数を machine epsilon ということがある。 それを調べるための初歩的なプログラム例を、 epsilon.p(Pascal) , epsilon.f(Fortran), epsilon.c(C) として置いてある。 このプログラムは、 キーボードから数値を eps という変数に読み、 eps を 1 とたして、合計が 1 と区別がつくかどうかを調べ、表示する。 これを、回数が決まっていないループの構造で繰り返している。 epsに読みこまれた数値が 0 の場合は、ループを脱出して止まる。 キーボードからの入力や、結果の表示は、通常(指数部なし)の小数の形、 または10を底とする浮動小数点表現で行なう。 読ませる数値をだんだん小さくしていき、どこまで行ったら区別が つかなくなるかを確認してほしい。

発展課題1: 「1とたして」ではなく、1とは桁の違う数(たとえば百万)と たしたら区別ができる限界の数値はどうなるだろうか? まず浮動小数点の考え方から予想し、それから実際に試してみよう。 epsilon.{p,f,c}はあとでまた使うのでそのままにし、 名前を変えたコピーを作って、変更(編集)、コンパイル、実行してみることを 勧める。

発展課題2: epsilon.{p,f,c}を改造し、ほんとうの意味で 「machine epsilonを求めるプログラム」にするにはどうしたらいいだろうか? たとえば、

ようにすれば、 machine epsilonの近似値(正しい値以上、その2倍未満)が求まる。

◎単精度と倍精度

浮動小数点数には、単精度と倍精度という区別があることが多い。 それが実際にどんな精度を意味するかは、機種やコンパイラごとに変わる。 ふつう、倍精度は単精度の2倍の記憶容量を使って表現する。 したがって、有効数字の桁数が約2倍になる。 (記憶容量のどれだけを指数部に分配するかが機種・コンパイラごとに 違うので、厳密に2倍というわけではない。) コンパイラによっては、単精度の4倍の記憶容量を利用する「4倍精度」 をもつものもある。

Fortran 77標準では、

と型宣言する。 現実には、 [2002年当時の慶応大学SFCの]CNSにあるSun SparcStationを含めて、多くの計算機で、 単精度を4バイト(32ビット)、倍精度を8バイト(64ビット)、 4倍精度は(もしあれば)16バイト(128ビット)で表現しているので、むしろ という形がよく使われる。この授業の例題でもこの形を使うことにする。

Pascalでは実数型はREALで、言語の標準としては精度を区別した型はないが、 たとえばかつてのDEC OSF/1(のちのCompaq Tru64 Unix) のPascalコンパイラでは、

という型宣言で区別される。(4倍精度は使えないコンパイラもある。)

C では

だが、doubleが圧倒的によく使われる。 なお、コンパイラによっては long doubleを4倍精度の意味とする もの、doubleと同じ意味とするもの、使えないものがある。

単精度、倍精度、4倍精度を比較するため、 さきの epsilon.{p,f,c}と基本的に同じプログラムを 精度を変えて用意した。

である。 (ただし4倍精度とPascalの倍精度については、あるコンパイラ用の例文であり、 各言語文法の標準だけで書かれているわけではない。) 倍精度の例文を実行して単精度と比較してみてほしい。

なお、それぞれの言語で、プログラム中に書く定数や、 読み書きする数値に精度の情報を添える表現が決められている。 epsilonの例文では、読みこんだ数値も表示するようにしてあるので、 読みこみの段階で精度落ちが起きていないか確認してほしい。

Fortran 77
Pascal
C

数値計算関係の問題では、倍精度を使うことを勧める。 これからの例題では特に断わりなく倍精度の変数を使うことがある。


1996-05-13; 2000-04-17; 2002-07-11, 2002-07-18, 2015-06-13
増田 耕一 (MASUDA Kooiti)

[目次へ]