ぺんぎんさんのおうち

日記です。たまに日記じゃないこともあります。

15.02.2024

mpf_class a("0.1")とmpf_class b = 0.1は違うんだなぁ。コンストラクタで呼び出す関数がそれぞれmpf_init_set_strとmpf_set_dなので違うのは当たり前なんだが、そうじゃない。

#include <iostream>
#include <gmpxx.h>

void dump_mpf_member(mpf_t t) {
    printf("Prec : %lu\n", t->_mp_prec);
    printf("Size : %lu\n", t->_mp_size);
    for (size_t i = 0; i < t->_mp_prec; i++) {
        printf("_mp_d_[%lu]: %lu\n", i, t->_mp_d[i]);
    }
}

int main() {
    mpf_class a("0.1");
    mpf_class b = 0.1;

    puts("mpf_t a");
    dump_mpf_member(a.get_mpf_t());
    gmp_printf("%.64Ff\n", a.get_mpf_t());
    puts("\nmpf_t b");
    dump_mpf_member(b.get_mpf_t());
    gmp_printf("%.64Ff\n", b.get_mpf_t());}
/*
$ ./a.out
mpf_t a
Prec : 2
Size : 3
_mp_d_[0]: 11068046444225730969
_mp_d_[1]: 11068046444225730969
0.1000000000000000000000000000000000000000000000000000000000000000

mpf_t b
Prec : 2
Size : 2
_mp_d_[0]: 0
_mp_d_[1]: 1844674407370955264
0.1000000000000000055510000000000000000000000000000000000000000000
*/

b = 0.1で0.1を評価するときに既に丸め誤差が発生している。0.1+0.1+0.1と0.3が等しくないやつ。一方でmpf_class a("0.1")では忠実に0.1を表現してくれる(限度はありそうやけど、正直わからん)。

ちなみにdouble型をmpf_t->_mp_dにセットする実装はextract-dbl.cにある。見ないほうがいい。 double型をmpf_tにセットしたいとき、単純に_mp_d[0] = double value;と書いてもダメそうだ。