LoginSignup
3
0

半精度浮動小数点型について

Last updated at Posted at 2023-12-20

ちょっとまだ普及したと言うには程遠いのではありますが。

そもそもこれは何か

概説はウィキペでも見てください。
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 単精度や倍精度の幅を短くした形になっています。

半精度浮動小数点型のビット配置図 - wikimedia

値の範囲と精度

主要な値は次の通り。なお、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 までオーバーフローしないので安心できる。
3
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0