ちょっとまだ普及したと言うには程遠いのではありますが。
そもそもこれは何か
概説はウィキペでも見てください。
IEEE 754-2008 には、16ビットを使って浮動小数点数を表現する新しい型 binary16 が導入されました。
もともと IEEE 754-2008 での言い方では interchange format といってデータ交換用で演算用ではなかったのですけれど、近年は画像処理のためGPGPUで半精度浮動小数点数の演算ができるものが現れ(NVIDIA Pascal以降らしい)、機械学習で活用されるようになりました。
CPUでもいまどきSIMD命令がありますから、ARM (A64fx) や x86_64 (Sapphire Rapids) でも半精度浮動小数点数の演算ができるものが出てきています。
すると、さまざまな局面で使えないのかと気になってきますね。とりあえず現状をまとめておきます。
言語処理系の対応
残念ながら x86 の Fortran で使えないというのが現況です。
x86_64 C
まずは GCC 12.3 以降で対応しています。Sapphire Rapids のネイティブ命令で高速に計算するためには -mavx512f16 オプション等を指定します。そうでなければエミュレーションを行う関数が呼ばれるようになって、それは libgcc 12 以降に含まれています。
また Intel OneAPI でも LLVM ベースの新コンパイラ(icx)ではサポートしています。GCCと同様に -mavx512f16 でネイティブコードが出ます。どうやらエミュレーションは libgcc に丸投げしている模様。
x86_64 Fortran
まだ対応している処理系については知りません。
[2023-12-20追記: 使ったことはありませんが、NAG Fortran が対応しているらしいです(演算ではなく変換のみ)。KIND値も独特です。
]
A64fx C
TCS C では Clang モード( -Nclang 指定時)に _Float16 型がサポートされます。
A64fx Fortran
TCS Fortran では -Nclang 指定の有無にかかわらず、 REAL(kind=2) 型がサポートされます。
データフォーマットの対応
netCDF ではまだ対応していないんだけれど議論はしているようです。
数値的特性
ビット配置図
ビット配置図を wikimedia から引用掲示します。IEEE 754 単精度や倍精度の幅を短くした形になっています。
値の範囲と精度
主要な値は次の通り。なお、quiet/signaling の区別と indefinite はインテル x86 での場合。
十六進表記 | 値 | 意義 |
---|---|---|
7FFF ... 7E00 | NaN | quiet NaN |
7DFF ... 7C01 | NaN | signaling NaN |
7C00 | Inf | 正の無限大 |
7BFF | 65504 | 正の有限数の最大 |
7800 | $2^{15} =$ 32768 | 2のべきの最大 |
4000 | 2.0 | |
3C00 | 1.0 | |
0400 | $2^{-14} =$ 6.10352e-05 | 正の有限数の最小 |
03FF | 6.09756e-05 | 正の非正規化数の最大 |
0001 | $2^{-24} =$ 5.96046e-08 | 正の非正規化数の最小 |
0000 | 0.0 | 正のゼロ |
8000 | -0.0 | 負のゼロ |
8001 ... 83FF | -5.96046e-08 ... -6.09756e-05 | 負の非正規化数 |
8400 ... FBFF | -6.10352e-05 ... -65504 | 負の有限数 |
FC00 | -Inf | 負の無限大 |
FC01 ... FDFF | NaN | signaling NaN |
FE00 ... FFFF | NaN | quiet NaN |
FFFF | NaN | quiet NaN indefinite |
また、有限数・非正規化数について、次のような精度になっている。
絶対値 | 値刻み | 注記 |
---|---|---|
32768 ... 65504 | $2^5$ = 32 | 一番精度が粗くなる場合 |
... | ||
1024 ... 2048 | $2^{0}$ = 1 | 2048 までの整数が正確に表現できる |
512.0 ... 1024.0 | $2^{-1}$ = 0.5 | |
256.0 ... 512.0 | $2^{-2}$ = 0.25 | |
128.0 ... 256.0 | $2^{-3}$ = 0.125 | |
64.0 ... 128.0 | $2^{-4}$ = 0.0625 | |
... | ||
2.0 ... 4.0 | $2^{-9}$ = 0.001953125 | |
1.0 ... 2.0 | $2^{-10}$ = 0.000976562 | |
0.5 ... 1.0 | $2^{-11}$ = 0.000488281 | |
... | ||
$2^{-14}$ ... $2^{-13}$ | $2^{-24} =$ 5.96046e-08 | 有限数の最小 |
$2^{-24}$ ... $2^{-14}$ | $2^{-24} =$ 5.96046e-08 | 非正規数は等間隔 |
C プログラミングとしての注意点
- -2048 ... 2048 の範囲の整数が正確に表現できる。
- 8ビット整数(C の unsigned char または signed char)を _Float16 に変換しても値は変わらない。
- 16ビット符号付き整数(通常は C の signed short)を _Float16 に変換すると、絶対値が2048より大きい場合値が丸められて誤差を生じるが、オーバーフロー(例外トラップまたは値 Inf の発生)は起こらない。
- 16ビット符号なし整数(通常は C の unsigned short)を _Float16 に変換すると、絶対値が2048より大きい場合値が丸められて誤差を生じるし、65504 ... 65535 の範囲についてはオーバーフロー(例外トラップまたは値 Inf の発生)が起こる。
気象データの伝達保存形式として考えると
GRIB や NuSDaS の諸問題に類似するわけですが:
- 浮動小数点値で -100.0 ... 100.0 程度の範囲に収まるものは、刻み 0.1 以下で表現できる。摂氏温度、雲量、相対湿度などが挙げられ、このような目的ではかなり満足できる。
- 絶対温度は 256.0 ... 512.0 の範囲となり、刻みは 0.25 となる。いくぶん精度が物足りない場合が多かろうから、摂氏温度への変換が定石となるだろう。仮数部の丸めの挙動などを気にするのであれば、摂氏温度よりも「絶対温度 - 256K」などのほうが好ましいかもしれないが、見慣れない表現は誤りのもとで避けたい。
- 海面更正気圧[hPa]は 1024 を超えることがあるので、刻みは 1 となる。これは実用上耐え難いので、摂氏温度と似た発想で「気圧 - 1000 hPa」などの値を保存することにならざるを得まい。
- ジオポテンシャル高度についても同様で、高度により異なるバイアスが避けられないだろう。
- 降水量 [kg/m2] については 1024 以下で 0.5 刻みなので、まあまあ満足できそう。しかも 65504 までオーバーフローしないので安心できる。