数値計算ガイド ホーム目次前ページへ次ページへ索引


第 2 章

IEEE 演算機能

この章では、ANSI/IEEE Standard 754-1985 for Binary Floating-Point Arithmetic (「IEEE 規格」または「IEEE 754」と略される) が規定する演算モデルについて説明します。SPARC、x86 のコンピュータはすべて、IEEE 演算機能を使用しています。サンのすべてのコンパイラ製品は、IEEE 演算機能をサポートしています。

IEEE 演算モデル

この節では、IEEE 754 について説明します。

IEEE の演算機能

IEEE 754 は、以下のことを規定しています。

IEEE 規格は、ユーザー定義の例外のサポートも提唱しています。

IEEE 規格が規定する機能により、区間演算、例外の遡及 (そきゅう) 診断、exp や cos のような標準的な基本関数の効率的な実装、多倍精度演算といった、数値計算に便利なさまざまなツールのサポートが可能になります。

IEEE 754 の浮動小数点演算は、他のいかなる浮動小数点演算よりも、優れた数値計算の可制御性を提供します。IEEE 規格は、実装時に厳格な要求を課すことにより、数学的に洗練された移植可能なプログラムを作成する作業を容易にするだけではありません。この規格は、これよりも拡張したり、洗練した実装も認めています。

IEEE 形式

この節では、浮動小数点データをメモリーに記憶する方法について説明します。また、各 IEEE 記憶形式の精度および範囲を示します。

記憶形式

浮動小数点形式とは、浮動小数点数を表わす数値フィールド、フィールドの配置、およびその解釈からなるデータ構造です。浮動小数点の記憶形式は、浮動小数点数をメモリーに記憶する形式を指定します。IEEE 標準はその書式を定義していますが、記憶形式の選択は実装者に任されています。

アセンブリ言語ソフトウェアは使用する記憶形式に依存しているものもありますが、高級言語の場合は通常、浮動小数点のデータ型の言語で表記できる部分だけを処理します。これらの型は、高級言語によって異なる名前を持ち、表 2-1 に示すように IEEE 形式に対応します。

表 2-1   IEEE 形式と言語の種類
IEEE 精度 C、 C++ FORTRAN
単精度 float REAL または REAL*4
倍精度 double DOUBLE PRECISION または REAL*8
拡張倍精度 long double REAL*16 (SPARC のみ)


IEEE 754 は、単精度と倍精度の浮動小数点形式を規定しており、これらの基本的な 2 つの形式に対して、それぞれ拡張形式のクラスを定義しています。表 2-1 にある long double と REAL*16 という言語の種類は、IEEE 標準で定義された拡張倍精度形式の 1 クラスです。

次の節では、SPARC 、x86 プラットフォームで IEEE 浮動小数点形式に使用される 3 つの記憶形式について詳しく説明します。

単精度の記憶形式

IEEE 単精度記憶形式は、23 ビットの小数部 f、8 ビットの指数 e、1 ビットの符号 s の 3 つのフィールドで構成されています。図 2-1 に示すように、これらのフィールドは、32 ビットワードを 1 つとして隣接して格納されます。ビット 0:22 には 23 ビット小数部 f が含まれます。ビット 0 が小数部の最下位ビット、ビット 22 が最上位ビットです。ビット 23:30 は 8 ビットのバイアス指数 e となり、ビット 23 はバイアス指数の最下位ビット、ビット 30 は最上位になります。最高位のビット 31 には符号ビット s が含まれます。

図 2-1   単精度の記憶形式

表 2-2 では、s、e、f の 3 つのフィールドにある値と、単精度の記憶形式ビットパターンで表示される値との対応を示しています。u は無意味です。つまり、示されたフィールドの値は、単精度記憶形式のこのビットパターンの値の決定には影響を及ぼさないということです。

表 2-2   IEEE 単精度記憶形式 のビットパターンで表現した値  
単精度ビットパターン 値
0 < e < 255 (-1)s × 2e-127 × 1.f (正規数)
(e = 0; f ≠ 0) (f にあるビットのうち最低 1 つはゼロ以外) (-1)s × 2-126 × 0.f (非正規数)
e = 0; f = 0 (f にあるビットはすべてゼロ) (-1)s × 0.0 (符号付きの 0)
s = 0; e = 255; f = 0
(f にあるビットはすべてゼロ)
+INF (正の無限大)
s = 1; e = 255; f = 0
(f にあるビットはすべてゼロ)
-INF (負の無限大)
s = u; e = 255; f ≠ 0 (f にあるビットのうち最低 1 つはゼロ以外) NaN (非数)


e < 255 の場合は注意してください。単精度の記憶形式ビットパターンに割り当てられた値は、2 進小数点を直ちに小数部の最大有効桁のすぐ左に挿入し、また暗黙のビットをその小数点のすぐ左に挿入して、2 進位取り記法で混合数を表示するように形成されます (0 <= 小数部 < 1 になるところで、全体の数に小数部を加える)。

このようにして形成された混合数は、単精度の記憶形式の有効数字と呼ばれます。暗黙のビットは、その値が明示的に単精度の記憶形式ビットパターンで与えられていませんが、バイアス指数フィールドの値によって暗示されるので、そのように命名されます。

単精度の記憶形式について、正規数と非正規数の相違点は、正規数の場合は有効数字の先行ビット (2 進小数点の左にあるビット) が 1 であるのに対して、非正規数の場合は 0 であることです。単精度記憶形式の非正規数は、IEEE 規格 754 では単精度記憶形式のデノーマル数と呼ばれていました。

暗黙の先行ビットと結合された 23 ビット小数部は、単精度形式の正規数で 24 ビットの精度を提供します。

単精度の記憶形式における重要なビットパターンの例を表 2-3 に示します。正の最大正規数は IEEE 単精度形式で表現可能な最大の有限数です。正の最小正規数とは IEEE 単精度形式で、精度を落とさずに表現可能な正の最小数です。最大非正規数とは、IEEE 単精度形式で表現可能な最大数です。正の最小の非正規数とは、IEEE 単精度形式で表現可能な正の最小数です。正の最小の正規数は、しばしばアンダーフローしきい値と呼ばれます。

表 2-3   単精度記憶形式でのビットパターンとその IEEE 値  
名前 ビットパターン
(16 進形式)
対応する値
+ 0
00000000
0.0
- 0
80000000
-0.0
1
3f800000
1.0
2
40000000
2.0
最大正規数
7f7fffff
3.40282347e+38
正の最小正規数
00800000
1.17549435e-38
最大非正規数
007fffff
1.17549421e-38
正の最小非正規数
00000001
1.40129846e-45
+
7f800000
+INF (正の無限大)
-
ff800000
-INF (負の無限大)
非数
7fc00000
NaN (数字以外)


NaN (非数) は、NaN の定義を満たすビットパターンのどれでも表現できます。表 2-3 に示した NaN の 16 進数値は、NaN を表現できる何種類ものビットパターンのうちの 1 つだけです。

倍精度の記憶形式

IEEE 倍精度値は、52 ビットの小数部 f、11 ビットの指数 e、1 ビットの符号 s の 3 つのフィールドで構成されています。図 2-2 に示すように、これらのフィールドは、続けてアドレス指定した 2 つの 32 ビットワードに隣接して格納されます。

SPARC アーキテクチャでは、上位アドレス 32 ビットワードに小数部の最下位 32 ビットが含まれます。一方 x86 および PowerPC アーキテクチャでは、下位アドレス 32 ビットワードに小数部の最下位 32 ビットが含まれます。

f[31:0] を小数の最下位 32 ビットで表わすと、ビット 0 は小数全体の最下位ビットになり、ビット 31 は 32 最下位小数ビットの最上位になります。

その他の 32 ビットワードでは、ビット 0:19 には小数部 f[51:32] の 20 の最上位ビットが含まれます。ビット 0 はこれらの 20 の最上位小数ビットの最下位になり、ビット 19 は小数全体の最上位ビットになります。ビット 20:30 は 11 ビットのバイアス指数 e で、ビット 20 はバイアス指数の最下位ビット、ビット 30 が最上位になります。最高位のビット 31 には符号ビット s が含まれます。

図 2-2 では、2 つの隣接する 32 ビットワードを介したビット数は、1 つの 64 ビットワードとなり、ビット 0:51 は 52 ビット小数部 f、ビット 52:62 は 11 ビットバイアス指数 e、ビット 63 は符号ビット s をそれぞれ格納します。


図 2-2   倍精度の記憶形式

これらの 3 つのフィールドにあるビットパターンの値は、全体のビットパターンによって表現される値を決定します。

表 2-4 では、s、e、f の 3 つのフィールドにある値と、倍精度の記憶形式ビットパターンで表示される値との対応を示しています。 u は無意味です。つまり、示されたフィールドの値は、倍精度記憶形式のこのビットパターンの値の決定には影響を及ぼさないということです。

表 2-4   IEEE 倍精度記憶形式のビットパターンで表現した値  
倍精度ビットパターン 値
0 < e < 2047 (-1)s × 2e-1023 × 1.f (正規数)
e = 0; f ≠ 0 (f にあるビットのうち最低 1 つはゼロ以外) (-1)s × 2-1022 × 0.f (非正規数)
e = 0; f = 0 (f にあるすべてのビットはゼロ) (-1)s × 0.0 (符号付きのゼロ)
s = 0; e = 2047; f = 0
(f にあるすべてのビットはゼロ)
+INF (正の無限大)
s = 1; e = 2047; f = 0
(f にあるすべてのビットはゼロ)
-INF (負の無限大)
s = u; e = 2047; f ≠ 0 (f にあるビットのうち最低 1 つはゼロ以外) NaN (非数)


e < 2047 の場合は注意してください。倍精度の記憶形式ビットパターンに割り当てられた値は、2 進基数点を直ちに小数部の最上位ビットに挿入し、また暗黙のビットを直ちにその 2 進小数点に挿入して形成されます。このように形成された数は仮数と呼ばれます。暗黙のビットは、その値が明示的に倍精度の記憶形式ビットパターンで与えられていませんが、バイアス指数フィールドの値によって暗示されているので、そのように命名されます。

倍精度の記憶形式について、正規数と非正規数の相違点は、正規数の場合仮数の先行ビット (2 進小数点の左にあるビット) は 1 であるのに対して、非正規数の場合は 0 であることです。倍精度記憶形式の非正規数は、IEEE 規格 754 では倍精度記憶形式のデノーマル数と呼ばれていました。

暗黙の先行仮数ビットと結合された 52 ビット小数部は、倍精度形式の正規数で 53 ビットの精度を提供します。

倍精度の記憶形式における重要なビットパターンの例を表 2-5 に示します。2 カラム目のビットパターンは、8 桁の 16 進数で表わされます。SPARC アーキテクチャでは、左は下位アドレス指定の 32 ビットワードの値、右は上位アドレス指定の 32 ビットワードの値になります。一方 x86 アーキテクチャでは、左が上位アドレスのワード、右が下位アドレスのワードになります。正の最大正規数とは、IEEE 倍精度形式で表現可能な最大の有限数です。正の最小正規数とは、IEEE 倍精度形式で、精度を落とさずに表現可能な正の最小数です。最大非正規数とは、IEEE 倍精度形式で表現可能な最大数です。正の最小非正規数とは、IEEE 倍精度形式で表現可能な正の最小数です。正の最小正規数は、アンダーフローしきい値とも呼ばれます。正の最大および最小の正規数および非正規数は、精度が失われる可能性があります。値は、以下の表のようになります。

表 2-5   倍精度記憶形式でのビットパターンとその IEEE 値  
名前 ビットパターン (16 進) 対応する値
+ 0
00000000 00000000
0.0
- 0
80000000 00000000
-0.0
1
3ff00000 00000000
1.0
2
40000000 00000000
2.0
最大正規数
7fefffff ffffffff
1.7976931348623157e+308
正の最小正規数
00100000 00000000
2.2250738585072014e-308
最大非正規数
000fffff ffffffff
2.2250738585072009e-308
正の最小非正規数
00000000 00000001
4.9406564584124654e-324
+
7ff00000 00000000
無限大
-
fff00000 00000000
- 無限大
非数
7ff80000 00000000
NaN


NaN (非数) は、NaN の定義を満たすビットパターンのどれでも表現できます。表 2-5 に示した NaN の 16 進数値は、NaN を表わすのに使用できる多くのビットパターンのうちの一例です。

拡張倍精度の記憶形式 (SPARC)

浮動小数点環境の 4 倍精度記憶形式は、IEEE 定義の拡張倍精度の記憶形式に準拠します。4 倍精度記憶形式では、4 つの 32 ビットワードを占有します。112 ビット小数部 f、15 ビットバイアス指数部 e、1 ビット符号 s の 3 つのフィールドから構成されています。図 2-3 に示すように、隣接して格納されています。

最高位アドレスの 32 ビットワードには、小数部 f[31:0] の最下位 32 ビットがあります。次の 2 つの 32 ビットワードにはそれぞれ、f[63:32] と f[95:64] が含まれます。次のワードのビット 0:15 には、小数部 f[111:96] の 16 最上位ビットが含まれ、ビット 0 はこれら 16 ビットの最下位になり、ビット 15 は小数部全体の最上位になります。ビット 16:30 には 15 ビットバイアス指数部 e が含まれ、ビット 16 はバイアス指数部の最下位、ビット 30 は最上位になります。また、ビット 31 には符号ビット s が含まれます。

図 2-3 では、4 つの隣接する 32 ビットワードを介したビット数は、1 つの 128 ビットワードとなり、ビット 0:111 は小数部 f、ビット 112:126 は 15 ビットバイアス指数 e、ビット 127 は符号ビット s をそれぞれ格納します。

図 2-3   拡張倍精度の記憶形式 (SPARC)

これら f、e、s の 3 つのフィールドにあるビットパターンの値は、全体のビットパターンによって表現される値を決定します。

表 2-6 では、s、e、f の 3 つのフィールドにある値と、4 倍精度の記憶形式ビットパターンで表示される値との対応を示しています。 u は無意味です。つまり、示されたフィールドの値は、拡張倍精度記憶形式のこのビットパターンの値の決定には影響を及ぼさないということです。

表 2-6   IEEE 拡張倍精度記憶形式のビットパターンで表現した値 (SPARC)  
拡張倍精度ビットパターン 値
0 < e < 32767 (-1)s × 2e-16383 × 1.f (正規数)
e = 0、f ≠ 0 (f のビットのうち最低 1 つはゼロ以外) (-1)s × 2-16382 × 0.f (非正規数)
e = 0、f = 0 (f のすべてのビットがゼロ) (-1)s × 0.0 (符号付きのゼロ)
s = 0、e= 32767、f = 0 (f のすべてのビットがゼロ) +INF (正の無限大)
s = 1、e= 32767、f = 0 (f のすべてのビットがゼロ) -INF (負の無限大)
s = u、e = 32767、f ≠ 0
(f のビットのうち最低 1 つはゼロ以外)
NaN (非数)


4 倍精度の記憶形式における重要なビットパターンの例を表 2-7 に示します。第 2 カラムのビットパターンは、8 桁の 16 進数で表わされています。一番左の数字が最低位アドレスの 32 ビットワードを、一番右の数字が最高位アドレスの 32 ビットワードを示しています。正の最大正規数とは、拡張倍精度形式で表現可能な最大の有限数です。正の最小正規数とは拡張倍精度形式で、精度を落とさずに表現可能な正の最小数です。最大非正規数とは、拡張倍精度形式で表現可能な最大数です。正の最小非正規数とは、拡張倍精度形式で表現可能な正の最小数です。正の最小正規数は、アンダーフローしきい値ともよばれます。正の最大および最小の正規数および非正規数は、精度が失われる可能性があります。値は、以下の表のようになります。

表 2-7   拡張倍精度記憶形式でのビットパターンとその値 (SPARC)  
名前 ビットパターン (SPARC) 対応する値
+0
00000000 00000000 00000000 00000000
0.0
-0
80000000 00000000 00000000 00000000
-0.0
1
3fff0000 00000000 00000000 00000000
1.0
2
40000000 00000000 00000000 00000000
2.0
最大正規数
7ffeffff ffffffff ffffffff ffffffff
1.1897314953572317650857593266280070e+4932
正の最小
正規数
00010000 00000000 00000000 00000000
3.3621031431120935062626778173217526e-4932
最大
非正規数
0000ffff ffffffff ffffffff ffffffff
3.3621031431120935062626778173217520e-4932
正の最小
非正規数
00000000 00000000 00000000 00000001
6.4751751194380251109244389582276466e-4966
+
7fff0000 00000000 00000000 00000000
+
-
ffff0000 00000000 00000000 00000000
-
非数
7fff8000 00000000 00000000 00000000
NaN


表 2-7 に示した NaN の 16 進数値は、NaN を表現できる何種類ものビットパターンのうちの 1 つにすぎません。

拡張倍精度の記憶形式 (x86)

浮動小数点環境の拡張倍精度記憶形式は、IEEE 定義の拡張倍精度の記憶形式に準拠します。63 ビット小数部 f、1 ビットの明示的先行仮数ビット j、15 ビットバイアス指数 e、1 ビット符号 s の 4 つのフィールドから構成されています。

x86 アーキテクチャファミリでは、これらのフィールドはアドレス指定した 8 ビットバイトが 10 個連続して格納されます。しかし、UNIX System V Application Binary Interface Intel 386 Processor Supplement (Intel ABI) では、倍拡張パラメータと結果がスタックで 3 つ連続した 32 ビットワードを占有し、図 2-4 にあるように使用されていない最高位アドレスのワードの最上位 16 ビットを持つようにしてください。

最下位アドレスの 32 ビットワードには、小数部 f[31:0] の最下位 32 ビットが含まれ、ビット 0 は小数部全体の最下位ビットになり、ビット 31 は 32 最下位小数ビットの最高位になります。中央のアドレス 32 ビットワードでは、ビット 0:30 には小数部 f[62:32] の 31 最高位ビットが含まれ、ビット 0 はこれら 31 最高位小数ビットの最下位になり、ビット 30 は小数部全体の最高位になります。この中央アドレスの 32 ビットワードのビット 31 には明示的な先行仮数ビット j が含まれます。

最高アドレスの 32 ビットワードでは、ビット 0:14 に 15 ビットバイアス指数部 e が含まれており、ビット 0 はバイアス指数部の最下位ビット、ビット 14 は最高位ビットになります。また、ビット 15 には符号ビット s が含まれます。この最高アドレス 32 ビットワードの最高位 16 ビットは x86 アーキテクチャファミリでは未使用ですが、この存在は上記で説明したように、Intel ABI への準拠には不可欠です。

図 2-4 では、3 つの隣接する 32 ビットワードを介したビット数は、1 つの 96 ビットワードとなり、ビット 0:62 は 63 ビット小数部 f、ビット 63 は明示的先行仮数ビット j、ビット 64:78 は 15 ビットバイアス指数 e、ビット 79 は符号ビット s をそれぞれ格納します。

   

図 2-4   拡張倍精度の記憶形式 (x86)

これら f、e、s、j の 4 つのフィールドにあるビットパターンの値は、全体のビットパターンによって表現される値を決定します。

表 2-8 は、隣接する 4 つのフィールドのカウントした数値と、ビットパターンで表現される値との対応を示しています。u は無意味です。つまり、示されたフィールドの値は、拡張倍精度記憶形式のこのビットパターンの値の決定には影響を及ぼさないということです。

表 2-8   IEEE 拡張倍精度記憶形式のビットパターンで表現した値 (x86)  
拡張倍精度ビットパターン (x86) 値
j = 0、0 < e < 32767 サポートしない
j = 1、0 < e < 32767 (-1)s × 2e-16383 × 1.f (正規数)
j = 0、e = 0; f ≠ 0� (f にあるビットのうち最低 1 つはゼロ以外) (-1)s × 2-16382 × 0.f (非正規数)
j = 1、e = 0 (-1)s × 2-16382 × 1.f (偽の正規数)
j = 0、e = 0, f = 0
(f にあるすべてのビットはゼロ)
(-1)s × 0.0 (符号付きのゼロ)
j = 1; s = 0; e = 32767; f = 0
(f にあるすべてのビットはゼロ)
+INF (正の無限大)
j = 1; s = 1; e = 32767; f = 0
(f にあるすべてのビットはゼロ)
-INF (負の無限大)
j = 1; s = u; e = 32767; f = .1uuu -- uu QNaN (シグナルを発生しない NaN)
j = 1; s = u; e = 32767; f = .0uuu -- uu � 0
(f にある u のうち最低 1 つはゼロ以外)
SNaN (シグナルを発生する NaN)


拡張倍精度形式のビットパターンは、暗黙的な先行仮数ビットを持たないので注意してください。先行仮数ビットは、拡張倍精度形式では、別のフィールド j として明示的に与えられます。しかし、e ≠ 0 のときは、このようなビットパターンを浮動小数点演算の演算子として使用すると、無効な演算例外が発生するという意味で、j = 0 をもつパターンはどれもサポートされません。

拡張倍精度形式での連帯しない j と f の結合を仮数と呼びます。e < 32767 および j = 1、あるいは e = 0 および j = 0 のとき、先行仮数ビット j と小数部の最上位ビットの間に小数点を挿入して仮数は形成されます。

x86 の拡張倍精度形式では、先行仮数ビット j が 0 でありバイアス指数部フィールド e も 0 であるビットパターンは非正規数を表現します。一方、先行仮数ビット j が 1 でありバイアス指数部フィールド e が 0 以外であるビットパターンは、正規数を表現します。先行仮数ビットは、指数の値から推定されるのではなく明示的に表現されるため、この形式は非正規数のようにバイアス指数部が 0 であるが先行仮数ビットが 1 であるビットパターンも認めます。このようなビットパターンはそれぞれ、実際には、バイアス指数部フィールドが 1 である対応するビットパターン (つまり正規数) と同じ値を表現します。そのため、これらのビットパターンは「疑似デノーマル」と呼ばれます (非正規数は IEEE 規格 754 でデノーマル数と呼ばれていました)。疑似デノーマルは、x86 拡張倍精度形式をコード化した結果にすぎず、オペランドとして示されるときには対応する正規数に暗黙的に変換されます。疑似デノーマルが結果として生成されることはありません。

拡張倍精度の記憶形式における重要なビットパターンの例を表 2-9 に示します。2 カラム目のビットパターンは、4 桁の 16 進数で表わされます。この数は最上位アドレス 32 ビットワードの下位 16 ビットです (この最高位アドレス 32 ビットワードの下位 16 ビットの再呼び出しは使用されないので、その値は表示されません)。これに 8 桁の 16 進のカウント数が 2 つ続きます。この左側は中央のアドレス 32 ビットワードの値、右側は下位アドレスの 32 ビットワードの値になります。正の最大正規数とは、 x86 拡張倍精度形式で表現可能な最大の有限数です。正の最小正規数とは拡張倍精度形式で、精度を落とさずに表現可能な正の最小数です。最大非正規数とは、拡張倍精度形式で表現可能な最大数です。正の最小非正規数とは、拡張倍精度形式で表現可能な正の最小数です。正の最小正規数は、アンダーフローしきい値ともよばれます。正の最大および最小の正規数および非正規数は、精度が失われる可能性があります。値は、以下の表のようになります。

表 2-9   拡張倍精度記憶形式でのビットパターンとその値 (x86)
名前 ビットパターン (x86) 対応する値
+0 0000 00000000 00000000 0.0
-0 8000 00000000 00000000 -0.0
1 3fff 80000000 00000000 1.0
2 4000 80000000 00000000 2.0
最大正規数 7ffe ffffffff ffffffff 1.18973149535723176505e+4932
正の最小正規数 0001 80000000 00000000 3.36210314311209350626e-4932
最大非正規数 0000 7fffffff ffffffff 3.36210314311209350608e-4932
正の最小非正規数 0000 00000000 00000001 3.64519953188247460253e-4951
+ 7fff 80000000 00000000 +
- ffff 80000000 00000000 -
最大小数部のあるシグナルを
発生しない NaN
7fff ffffffff ffffffff QNaN
最小小数部のあるシグナルを
発生しない NaN
7fff c0000000 00000000 QNaN
最大小数部のあるシグナルを
発生する NaN
7fff bfffffff ffffffff SNaN
最小小数部のあるシグナルを
発生する NaN
7fff 80000000 00000001 SNaN


NaN (非数) は、NaN の定義を満たすビットパターンのどれでも表現できます。表 2-9 に示した NaN の 16 進数値は、小数フィールドの先行 (たとえば最上位) ビットが NaN はシグナルを発生しないか (先行小数ビットは 1)、発生するか (先行小数ビットは 0) を決定するポイントを示しています。

10 進表現の範囲と精度

この節では、指定された記憶形式の範囲と精度の表記法について簡単に説明します。IEEE の単精度形式、倍精度形式、SPARC、x86 アーキテクチャでの IEEE 拡張倍精度形式の実装に準拠する範囲と精度について説明します。具体的には、範囲と精度の表記法に関する説明で IEEE の単精度形式を取りあげます。

IEEE 規格では、単精度形式で浮動小数点を表わす場合は 32 ビットを使用することを規定しています。32 個の 0 と 1 の組合せには限りがあるので、32 ビットで表現できる数だけが使用されることになります。

そこで次のような疑問がおこります。

「この特定の形式で表わすことができる最大の正の数と最小の正の数を 10 進数で表現したらどうなるか」

この疑問を次のように言い換えて、範囲の概念を説明します。

「IEEE 単精度形式で表現できる数の範囲を 10 進数で表現するとどうなるか」

IEEE の単精度形式の厳密な定義をふまえると、IEEE の単精度形式で表現できる浮動小数点数の範囲 (正の正規数に限る) は以下の通りです。

1.175...x (10-38) から 3.402...x (10+38) まで

次に問題になるのは、指定された形式で表現する数の精度 (正確度または有効数字と混同させないため) です。この表記法については、図と例を提示して説明します。

2 進浮動小数点演算の IEEE 標準は、単精度形式で表現できる数値の集合を規定します。この数値の集合は、2 進浮動小数点数の集合として説明されていたことを思い出してください。IEEE 単精度形式の仮数は 23 ビットで、暗黙の先行ビットと結合し、(2 進) 精度の 24 桁 (ビット) になります。

一方、以下の数直線のように数 x = (x1.x2 x3...xq) x (10n) (仮数 q は 10 進数字で表現可能な数) にマーキングをして違う数値の集合を取得します。

    

図 2-5   10 進と 2 進表現で定義された数の比較

この 2 つの集合は別のものなので注意してください。そのため、2 進数の仮数 24 に対応する仮数 10 進数を算定すると、問題を再度まとめるように求められます。

2 進表現 (コンピュータが使用する内部形式) と 10 進形式間の浮動小数点数の変換という見地で、問題をもう一度明確にしてみます。ここでは、2 進から 10 進へ変換して 2 進 に戻すとともに、10 進から 2 進 に変換して 10 進に戻してみます。

数値の集合はそれぞれ違うので、一般に変換は不正確だということを認識することが必要です。正しく変換が行われた場合、ある集合の数値から別の集合の数値に変換すると、変換先のセットから隣接した 2 数のうち 1 つを選択する結果になります。

最初にいくつか例をみてみます。 たとえば、次の 10 進形式の数を IEEE 単精度形式で表現するとします。

x = x1.x2 x3... × 10n

IEEE の単精度形式で正確に表現できる実数の数には限度があり、上記形式によるすべての数値がそれらに含まれるわけではないため、通常はそのような数値を正確に表現することは不可能です。次の例を考えてみます。

y = 838861.2, z = 1.3

ここで、以下の FORTRAN プログラムを実行します。

    REAL Y, Z
    Y = 838861.2
    Z = 1.3
    WRITE(*,40) Y
40  FORMAT("y: ",1PE18.11)
    WRITE(*,50) Z
50  FORMAT("z: ",1PE18.11)

このプログラムからの出力は、次のようになります。

y:  8.38861187500E+05
z:  1.29999995232E+00

y に代入された値 8.388612 × 105 と出力された値の差は、0.000000125 です。すなわち、y よりも小数点以下 7 桁分少なくなっています。この場合、y を IEEE の単精度形式で表わしたときの正確度は、約 6 桁または 7 桁の有効数字です。言い換えると、y を IEEE の単精度形式で表現した場合の有効数字は約 6 桁になります。

同様に、z に代入された値 1.3 と出力された値の差は、0.00000004768 です。すなわち、z よりも小数点以下 8 桁分少なくなっています。この場合、z を IEEE 単精度形式で表わしたときの正確度は、約 7 桁または 8 桁の有効数字です。つまり、z を IEEE の単精度形式で表現した場合の有効数字は約 7 桁になります。

この問題を公式化してみます。

「10 進数の浮動小数点数 a を IEEE の単精度形式 2 進表現 b に変換し、さらに b を 10 進数の c に変換すると、a と a - c の差は何桁分になるか。」

この問題は次のように言い換えることができます。

「IEEE 単精度形式 a の有効な 10 進桁はいくつか。言い換えると、x を IEEE 単精度形式で表わした場合、何桁の 10 進数を正確であるとみなすべきか。」

有効 10 進数の桁数は、常に 6 から 9 です。すなわち、正確なのは 6 桁以上 9 桁以下です (変換が正確であり、無限大の桁が正確であるとみなす場合を除きます)。

言い換えると、IEEE 単精度形式で 2 進数を 10 進数に変換して、それをまた 2 進数に戻した場合、一般的にはこれらの 2 回の変換を行なった後に最初の数を得るためには、最低 9 桁の 10 進数が必要です。

値は表 2-10 のようになります。

表 2-10   各記憶形式の範囲と精度
形式 有効数字 2 進表現 最小の正の正規数 最大の正の数 有効数字の10 進表現
単精度 24 1.175... 10-38 3.402... 10+38 6-9
倍精度 53 2.225... 10-308 1.797... 10+308 15-17
拡張倍精度 (SPARC) 113 3.362... 10-4932 1.189... 10+4932 33-36
拡張倍精度 (x86) 64 3.362... 10-4932 1.189... 10+4932 18-21


Solaris 環境における基数変換

C の printf や scanf、FORTRAN の read、write、print のような入出力ルーチンでは、基数変換が使用されます。これらの関数では、2 進と 10 進の数値表現の間で変換が必要です。

Solaris 環境では、標準 C ライブラリの libc にすべての言語における基数変換のための基本ルーチンが含まれています。これらのルーチンは、任意の入力形式と出力形式の間で正しい丸め変換を行うテーブル駆動型のアルゴリズムを使用します。テーブル駆動型のアルゴリズムは正確であるうえに、正しく丸められた基数変換が最悪のケースになってしまう回数を減らすことができます。

IEEE 規格は、絶対値が 10-44 〜 10+44 である典型的な数値の場合、正確な丸めを要求しますが、比較的大きな指数部の場合には多少の不正確な丸めも認めています (IEEE 規格 754 の 5.6 を参照)。libc のテーブル駆動型アルゴリズムは、単精度、倍精度、および拡張倍精度形式の全範囲について正しい丸めを行います。

基数変換に関する参照マニュアルについては、付録 F を参照してください。優れた文献として、特に Coonen の論文と Sterbenz の書籍をお勧めします。

アンダーフロー

アンダーフローは、算術演算の結果が小さすぎるために、通常より大きな丸め誤差をおこさないと指定形式に格納できない場合に発生します。

アンダーフローしきい値

表 2-11 に、単精度、倍精度、および拡張倍精度の場合のアンダーフローしきい値を示します。

表 2-11   アンダーフローしきい値  
宛先精度 アンダーフローしきい値
単精度 最小の正規数 最大の非正規数 1.17549435e-38 1.17549421e-38
倍精度 最小の正規数 最大の非正規数 2.2250738585072014e-308 2.2250738585072009e-308
拡張倍精度 (SPARC) 最小の正規数 最大の非正規数 3.3621031431120935062626778173217526e-4932 3.3621031431120935062626778173217520e-4932
拡張倍精度 (x86) 最小の正規数 最大の非正規数 3.36210314311209350626e-4932 3.36210314311209350590e-4932

正の非正規数は、最小の正規数とゼロの間にある数です。最小の正規数に近い 2 つの (正の) 小さい数の減算を行うと、非正規数が生じます。あるいは、最小の正規数を 2 で割ると、商は非正規数になります。

非正規数そのものは正規数より少ないビット数の精度ですが、非正規数が存在すると、小さい数を含む浮動小数点計算はより大きな精度が可能となります。数学的に正しい結果が正の最小正規数よりも小さい時に、(ゼロを答えとして返すのではなく) 非正規数を生成することは、段階的アンダーフローとして知られています。

このようなアンダーフローの結果を扱う方法はいくつかあります。以前は共通の方法として、結果をゼロにしていました。この方法は Store 0 として知られ、IEEE 標準ができる以前はメインフレームのデフォルト値になっていました。

IEEE 規格 754 を起草した数学者およびコンピュータ設計者は、数個の代替方法を考案し、数学的に安定した解および、効率よく実装することができる標準を生成する必要性をどちらも満たすように改良しました。

IEEE 演算機能におけるアンダーフローの扱い

IEEE 規格 754 はアンダーフロー結果を扱う望ましい方法として、段階的アンダーフローを選択しています。この方法は、正規数と非正規数の 2 つの格納された値に対する表現を定義することになります。

正規浮動小数点数の IEEE 形式は次のようになっています。

s は符号ビット、e はバイアス指数、f は小数部です。数を完全に指定するには、s、e、および f を格納する必要があります。有効数字の暗黙の先行ビットは、正規数の場合 1 に定義されるので、格納する必要はありません。

格納できる最小の正の正規数は、最大の負の指数とオールゼロの小数部を持ちます。先行ビットを 1 でなくゼロにすれば、さらに小さい数でも収容することができます。倍精度形式の場合、小数部は 52 ビット長 (10 進で約 16 桁) なので、最小指数を 10-308 から 10-324 に拡張できます。これらは非正規数です。(アンダーフローした結果をゼロにフラッシュしないで) 非正規数を返すことが段階的アンダーフローです。

非正規数が小さければ小さいほど、当然ながらゼロ以外のビット数は少なくなります。非正規数を生じる計算は、相対丸め誤差の限界が正規オペランドの計算と同じではありません。しかし、段階的アンダーフローで重要なのは、これを使用することが以下のことを意味している点です。

非正規浮動小数点数の IEEE 形式は次のようになっています。

s は符号ビット、バイアス指数 e はゼロ、f は小数部となります。暗黙の底 2 の累乗は正規形式の底より 1 大きく、小数部の暗黙の先行ビットはゼロであることに注意してください。

段階的アンダーフローを利用すると、表現できる数の範囲をより小さくすることができます。値を疑わしいものにする小ささではなく、関連誤差です。非正規数を利用するアルゴリズムは、そうでないシステムより誤差の境界が小さくなります。次の節では、段階的アンダーフローの数学的正当性を示します。

段階的アンダーフローの利点

非正規数の目的は、それ以外の演算機能のように、アンダーフロー/オーバーフローを完全に避けることではありません。非正規数は、多様な計算 (代表的には、乗算の次に加算を行う場合) を配慮した上でアンダーフローを削除します。詳細については、James Demmel 著『Underflow and the Reliability of Numerical Software』および
S.Linnainmaa 著『Combatting the Effects of Underflow and Overflow in Determining Real Roots of Polynomials』を参照してください。

演算に非正規数があると、トラップされないアンダーフロー (正確度が損なわれることを意味します) は、加算または減算では発生しません。このため、x と y が 2 の因数の中であれば、x - y には誤差が生じません。これは、アルゴリズムの重要な場所で現在の精度を実質的に増すアルゴリズムでは絶対に必要なことです。

また、段階的アンダーフローは、アンダーフローによる誤差が通常の丸め誤差ほどひどくないことを意味しています。これは他のアンダーフロー処理方法よりもはるかに有力です。この事実は、段階的アンダーフローが最も正当化される理由の 1 つです。

段階的アンダーフローの誤差特性

浮動小数点の結果は、ほとんどの場合に丸められます。

computed result = (true result)±roundoff

丸めの最大サイズはどれくらいでしょうか。そのサイズを測る便利な方法の 1 つに「最後の場所の単位」(unit in the last place、ulp と略される) があります。標準表記における浮動小数点数の仮数の最下位ビットが最後の場所になります。このビットが表現する値 (たとえば、このビットを除いて表現がまったく同じである 2 つの数値間の絶対値の差) は、その数値の「最後の場所の単位」です。実際の結果を表現可能な最近似値に丸めることにより計算結果が取得される場合は、計算結果の最後の場所の単位の半分より丸め誤差が大きくなることはありません。つまり、IEEE 演算では、最近似の丸めモードによって計算結果は次のようになります。

0 ≦ |roundoff| ≦ 1/2 ulp

ulp は相対量です。非常に大きな数値の場合、その ulp も同様に大きくなります。一方、小さな数字の場合にはその ulp は小さくなります。この関係は、ulp を関数として表現することにより明示化できます。ulp(x) は、浮動小数点数 x の最後の場所の単位を示します。

浮動小数点数の ulp は、その数値が表現される精度により異なります。たとえば、上記で説明した浮動小数点の 4 つの形式における ulp(1) の値は、次のようになります。

表 2-12   4 つの異なる精度における ulp(1)
精度 値
単精度 ulp(1) = 2^-23 〜 1.192093e-07
倍精度 ulp(1) = 2^-52 〜 2.220446e-16
拡張倍精度 (x86) ulp(1) = 2^-63 〜 1.084202e-19
4 倍精度 (SPARC) ulp(1) = 2^-112 〜 1.925930e-34


どのコンピュータ演算でも正確に表現できる数はごく限られています。数値が小さくなり、ゼロに近づくに従って、隣接した表現可能な数の差は狭まっていきます。逆に数値が大きくなるに従い、隣接した表現可能な数の差は広がっていきます。

たとえば、精度がわずか 3 ビットである 2 進演算を行なったとします。その場合、2 つの 2 の累乗値の間には図 2-6 に示す通り 23 = 8 個の表現可能数があります。

   

図 2-6   数直線

この数直線は、ある指数から次の指数までの数の差が、実質的に 2 倍になることを示しています。

IEEE 単精度形式の場合、2 つの最小の正の非正規数の差は約 10-45 ですが、2 つの最大の無限大数の差は約 1031 になります。

表 2-13 では、数直線上を正の無限大方向に移動していくときに、nextafter (x,+ ) が示す x の次に表現可能な数字を示します。

表 2-13   表現可能な単精度浮動小数点数の差
x nextafter(x, + ) 差
0.0 1.4012985e-45 1.4012985e-45
1.1754944e-38 1.1754945e-38 1.4012985e-45
1.0 1.0000001 1.1920929e-07
2.0 2.0000002 2.3841858e-07
16.000000 16.000002 1.9073486e-06
128.00000 128.00002 1.5258789e-05
1.0000000e+20 1.0000001e+20 8.7960930e+12
9.9999997e+37 1.0000001e+38 1.0141205e+31


従来の表現可能浮動小数点数の場合、不正確な結果の及ぼす最悪の影響は、計算結果の隣の表現可能数までの距離よりも大きい誤差を生じるという特性を持っていました。非正規数を表現可能数の集合に追加し、段階的アンダーフローを実装した場合、不正確な結果またはアンダーフロー結果の及ぼす最悪の影響は、計算結果の隣の表現可能数までの範囲で誤差を生じることです。

特にゼロと最小の正規数の間では、2 つの隣り合った数の差は、ゼロと最小の非正規数の差と等しくなります。非正規数があると、極限近似表現可能数までの範囲より大きい丸め誤差を生じる可能性をなくすことができます。

計算結果の表現可能な隣の数までの範囲を越えた丸め誤差を生じる計算がないため、確かな演算環境には、以下の 3 つの重要な特性があります。

代替のアンダーフロー機能は、Store 0 です (アンダーフロー結果をゼロにフラッシュします)。Store 0 は、x-y がアンダーフローすると 1 つめと 2 つめの特性に反します。また、1/x がアンダーフローすると、3 つめの特性に反します。

λは、アンダーフローのしきい値でもある最小の正の正規数です。ここで、段階的アンダーフローと Store 0 の誤差特性を比較できます。

gradual underflow: |error| < ulp in λ
Store 0:       |error| λ

λの最後の位置の 単位と、λの間には有意差があります。

段階的アンダーフローと Store 0 の 2 つの例

以下に、有名な数学的例題を 2 つ示します。最初の例は内積です。

sum = 0; 
for (i = 0; i < n; i++) {
	sum = sum + a[i] * y[i]; 
} 
result = sum ; 

段階的アンダーフローの場合、result は丸めと同程度に正確です。Store 0 の場合、小さな小計 (ゼロでない) を出すことができます。これは一見正しくみえますが、ほとんどの桁が間違っています。このような問題を解決するには、プログラマが詳細化によって正確度が低下すると予想できる場合、計算を各数値の比を保って何倍かにすることを認めなければなりません。

もう 1 つの例は、複素数の商を得る場合で、この場合は各数値の比を保って何倍かにする必要はありません。

、 と仮定する

と がそれぞれわずかな ulp 以下の誤差を含む場合、丸めによる部分を考慮しても、計算結果の複素数と正しいと予想される結果には、誤差があることがわかります。誤差分析によると、a と b の両方がアンダーフローである場合を除いて、アンダーフローがあっても誤差は のわずかな ulp 以下になります。アンダーフローがゼロにフラッシュされると、どちらの例題も真ではなくなります。

複素数の商を計算するこのアルゴリズムは正確なので、段階的アンダーフローが発生しても、誤差分析を行う必要はありません。同様に Store 0 の場合、複素数の商を計算するための正確で分析しやすい有効なアルゴリズムはありません。Store 0 の場合、下位レベルの複雑で詳細な処理については、浮動小数点環境の実装側ではなくユーザー側に移行されています。

段階的アンダーフローが発生しても成功しますが、Store 0 を使うと失敗する問題の種類は、Store 0 の使用者が認識しているよりもたくさんあります。よく使用される数値演算は以下の種類に分けられます。

アンダーフローは問題か

これらの例にもかかわらず、アンダーフローがまれに問題となり、なぜ問題になるのか議論になることがあります。しかし、これは論理的には間違っています。

段階的アンダーフローの機能がないと、ユーザープログラムは暗黙の不正確なしきい値に対して注意を払わなければなりません。たとえば単精度の場合、計算のある部分でアンダーフローが発生し、アンダーフローした結果が Store 0 命令により 0 に置き換わると、正確度は、単精度指数の通常の低いほうの範囲 10-38 ではなく 10-31 程度しか保証できません。

これは、不正確なしきい値に近づいたことを知る方法を実現するか、確かで安定したアルゴリズムの実現を放棄するか、どちらかを行わなければならないことを意味します。

ゼロ近くに収束した領域で計算が起こらないように、数値を大きくするアルゴリズムもあります。しかし、各数値計算プログラムにおいて、アルゴリズムをゼロ近くで計算が起こらないようにして、不正確なしきい値を検出する作業は困難であり、時間の浪費になります。


サン・マイクロシステムズ株式会社
Copyright information. All rights reserved.
ホーム   |   目次   |   前ページへ   |   次ページへ   |   索引