IEEE 754の十進浮動小数点数の基本
浮動小数点形式
IEEE 754で規定された浮動小数点形式は、基数
指数部の最小値
浮動小数点数として表現できる実数は、
と表現できるものです。
例えば
二進形式の場合は正規化数に対して
(符号ビットも含めて)同じ数を表す表現の集合をその数のcohortと呼びます。
同じ数に対する複数の表現(
ビット列での表現
IEEE 754では、いくつかの浮動小数点形式に対してビット列での表現を定めています。これらの形式のことを交換形式 (interchange format)と呼びます。
十進交換形式のビット列による表現は、二進交換形式の場合と同様に、おおまかに3つの部分に分かれます:
←上位 | 符号 |
合成フィールド |
仮数部 |
下位→ |
---|---|---|---|---|
1ビット |
|
|
よく使われる十進交換形式は、以下の3つです:
decimal32 | decimal64 | decimal128 | |
---|---|---|---|
ビット幅 |
32 | 64 | 128 |
精度(桁数) |
7 | 16 | 34 |
指数部の最大値 |
96 | 384 | 6144 |
指数部のバイアス | 101 | 398 | 6176 |
符号ビット | 1 | 1 | 1 |
合成フィールドの幅(ビット数) |
11 | 13 | 17 |
仮数部の幅(ビット数) |
20 | 50 | 110 |
IEEE 754では、十進交換形式のビット列へのエンコード方法を十進エンコーディング (decimal encoding)と二進エンコーディング (binary encoding)の二種類規定しています。これらは互換性がないので、プラットフォームのABIや使用するプロトコルがどちらかを決めなければなりません。
十進エンコーディングは仮数部をDPD (densely packed decimal)と呼ばれる10ビットに十進3桁を詰め込む方式で表現します。10ビット=1024通りと十進3桁=1000通りが近いので(古のBCD (binary-coded decimal)と比べて)効率的、ということのようです。
二進エンコーディングは仮数部を二進整数で表現します。BID (binary integer decimal)と呼ばれることもあります。
いずれのエンコーディングでも、浮動小数点数の表現
それぞれの具体的なエンコード方法はここでは解説しません。IEEE 754を読んでください。
ハードウェア実装とABI
IBM POWERシリーズやZシリーズはハードウェアでIEEE 754の十進浮動小数点形式をサポートしているらしいです。エンコーディングは十進(DPD)らしいです。
他の環境では、ソフトウェア実装を使うことになります。
ABI的には、POWER向けのABIでは十進(DPD)、x86_64向けのSystem V ABIやAArch64の標準呼び出し規約
では二進(BID)となっているようです。
RISC-Vでは "L" 拡張が十進浮動小数点数用ということになっていますが、レジスターを既存の浮動小数点数用のものと共用すること以外何も決まっていないようです。エンコーディングが十進か二進かすら、ABIの文書を見る限りまだ決まってなさそうです。
ハードウェア実装はともかく、せめて十進エンコーディングか二進エンコーディングかを決めてもらわないとソフトウェア実装すら使えないのは厄介なところです。
C言語での扱い
今年出るC言語の規格C23では十進浮動小数点数のサポートが盛り込まれます。ただ、例によってオプショナルな機能という扱いで、処理系がマクロ __STDC_IEC_60559_DFP__
を定義している場合に使えることになっています。
提供される型の名前は _Decimal32
, _Decimal64
, _Decimal128
です。処理系がさらに __STDC_IEC_60559_TYPES__
を定義している場合は他の _Decimal〈N〉
も使えるかもしれません。
リテラルのサフィックスは d〈N〉
ですが、_Decimal32
, _Decimal64
, _Decimal128
に対しては df
, dd
, dl
, DF
, DD
, DL
も使えます。2文字目は float
/double
/long double
を意識したものだと思われます。十六進リテラルは使えません。
複素数には対応しません。
入出力のフォーマットの際の長さ修飾子 (length modifier)は
-
H
:_Decimal32
-
D
:_Decimal64
-
DD
:_Decimal128
です。変換指定子 (conversion specifier)は a
, A
, e
, E
, f
, F
, g
, G
のいずれかに対応します。
十進型に対する各種関数を使うには、ヘッダーを #include
する前に __STDC_WANT_IEC_60559_TYPES_EXT__
を定義しておく必要があります。
数学関数のサフィックスは d〈N〉
です。例えば
#define __STDC_WANT_IEC_60559_TYPES_EXT__
#include <math.h>
_Decimal32 sind32(_Decimal32 x);
_Decimal64 sind64(_Decimal64 x);
_Decimal128 sind128(_Decimal128 x);
という具合です。
最近のGCCはいくつかのターゲットで十進浮動小数点数型をサポートしています:
が、主要なlibc実装はまだ十進浮動小数点数をサポートしていないようです(IBMのプラットフォーム用のやつだと違うのかもしれない)。
IEEE以外の十進浮動小数点数
プログラミング環境によっては、IEEE 754とは無関係な十進浮動小数点数を提供していることがあります。例をいくつか挙げます。
Microsoft
OLEとか.NETで Decimal
型が使えます。
表現できる数は
Java
Javaは任意精度の BigDecimal
型を提供しています。負のゼロ、無限大、NaNはありません。
Python
Pythonは任意精度の decimal
モジュールを提供しています。負のゼロ、無限大、NaNを含みます。
Discussion