さまざまなnビットのバイナリ浮動小数点形式をエミュレートしたいと思います。それぞれに指定されたe_maxとe_minがあり、pビットの精度があります。これらの形式で、IEEE-754 標準に忠実な非正規数をエミュレートしたいと考えています。
当然のことながら、検索の結果、IEEE-754 に準拠し、関数でサブノーマルをサポートできる MPFR ライブラリにたどり着きましたmpfr_subnormalize()
。ただし、サブノーマル対応環境を正しくセットアップするためにmpfr_set_emin()
と を使用すると、いくつかの混乱に遭遇しました。mpfr_set_emax()
これは MPFR マニュアルで使用されている例であるため、サンプル形式として IEEE 倍精度を使用します。
http://mpfr.loria.fr/mpfr-current/mpfr.html#index-mpfr_005fsubnormalize
mpfr_set_default_prec (53);
mpfr_set_emin (-1073); mpfr_set_emax (1024);
上記のコードは、上記のリンクの MPFR マニュアルからのものです。e_maxもe_minもの期待値と等しくないことに注意してくださいdouble
。ここで、pはdouble
タイプから予想されるように 53 に設定されていますが、e_maxは正しい値の 1023 ではなく 1024 に設定されており、e_minは -1073 に設定されています。-1022 の正しい値を大きく下回っています。指数の境界をきつく設定しすぎると、MPFR の中間計算でオーバーフロー/アンダーフローが発生することは理解していますが、e_minを正確に設定することが正しい非正規数を確保するために重要であることがわかりました。高すぎたり低すぎたりすると、MPFR の結果 ( で更新mprf_subnormalize()
) が対応する結果とは異なります。double
結果。
私の質問は、指数境界e_maxとe_minを持つ浮動小数点形式の正しい非正規動作を保証するために、どの値をmpfr_set_emax()
and (特に)に渡すかをどのように決定する必要があるかということです。この問題に関する詳細な文書や議論はないようです。mpfr_set_emin()
心より感謝申し上げます。
ジェームズ。
EDIT 30/07/16: これは、単精度数のe_maxとe_minの選択を示す小さなプログラムです。
#include <iostream>
#include <cmath>
#include <float.h>
#include <mpfr.h>
using namespace std;
int main (int argc, char *argv[]) {
cout.precision(120);
// IEEE-754 float emin and emax values don't work at all
//mpfr_set_emin (-126);
//mpfr_set_emax (127);
// Not quite
//mpfr_set_emin (-147);
//mpfr_set_emax (128);
// Not quite
//mpfr_set_emin (-149);
//mpfr_set_emax (128);
// These float emin and emax values work in subnormal range
mpfr_set_emin (-148);
mpfr_set_emax (128);
cout << "emin: " << mpfr_get_emin() << " emax: " << mpfr_get_emax() << endl;
float f = FLT_MIN;
for (int i = 0; i < 3; i++) f = nextafterf(f, INFINITY);
mpfr_t m;
mpfr_init2 (m, 24);
mpfr_set_flt (m, f, MPFR_RNDN);
for (int i = 0; i < 6; i++) {
f = nextafterf(f, 0);
mpfr_nextbelow(m);
cout << i << ": float: " << f << endl;
//cout << i << ": mpfr: " << mpfr_get_flt (m, MPFR_RNDN) << endl;
mpfr_subnormalize (m, 1, MPFR_RNDN);
cout << i << ": mpfr: " << mpfr_get_flt (m, MPFR_RNDN) << endl;
}
mpfr_clear (m);
return 0;
}