C++ で #include <limits> をして std::numeric_limits<__float128>::digits をすると 0 と返ってきました。
よって、__float128 は float にすら劣る桁数しかないことがわかりました。いかがでしたか?
コード
#include <math.h> #include <stdio.h> #define MAGIC 0x7EEE #define PRECISION(F) lround(-log2((F)((F)1 - (F)((F)((F)1 / (F)MAGIC) * (F)MAGIC)))) int main(void) { printf("%ld\n", PRECISION(_Float16)); // 11 printf("%ld\n", PRECISION(float)); // 24 printf("%ld\n", PRECISION(double)); // 53 printf("%ld\n", PRECISION(long double)); // 64 printf("%ld\n", PRECISION(__float128)); // 113 }
雑談
各浮動小数点型 _Float16, float, double, long double, __float128 に対して、それぞれの仮数部の桁数を $p$ bits として
$$(1\oslash \roundp{\texttt{7EEE}_{(16)}})\otimes\roundp{\texttt{7EEE}_{(16)}} = 1 - 2^{-p}$$
が成り立つことを利用しています。
丸めモードは tiesToEven を前提としているのと、これ以外の仮数部の型については知りません。便宜上 long double の仮数部が 64 bits であるかのように書いていますが、処理系によって 53 bits だったり 113 bits だったりすることもあります。
なお、_Float16 においては $1\oslash 16384$ 未満で (graceful) underflow してしまうことに注意しましょう。
今まではそういう状況を考慮する必要がなかったので、$\oslash$ などの演算子に対して「仮数部が $p$ bits で丸めモードが tiesToEven で、〜」とだけ思っていましたが、厳密には指数部の桁数も考慮する必要がありますね*1。
promotion によって double 未満の型が double に変換されるため、いちいち (F) でキャストし直しています。
挙動を見た感じだと _Float16 は promote しないように見えました。float だけ?
_Float16 については 6.13 Half-Precision Floating Point を読むとよいかもしれません。__fp16 は使えたり使えなかったりしそうです。
おわり
おわりです。 この記事が役に立たないことを祈ります。
*1:カスの記事だとしても、書いているうちに気づきを得られる例。