コイン投げ #10

> 6桁表示なら精度はこのデフォルトで十分だった。
は誤りであることに気付いた。
最終的に必要な桁数が6桁であるからmain関数のmpfr_t型変数pの精度はデフォルトで十分、
というロジックが間違っている。

int prob(mpfr_t p, unsigned int a, unsigned int b)
...snip
    mpfr_set_z(p, x, GMP_RNDN);
    mpfr_div_z(p, p, y, GMP_RNDN);

なので、pの精度はmpfr_div_z関数による最終的な割り算の結果に影響を与えるだけでなく、
割り算前のmpfr_set_z関数による代入の結果、すなわち割られる数自体にも影響を与えるからである。

int prob(mpfr_t p, unsigned int a, unsigned int b)
...snip
    mpfr_set_z(p, x, GMP_RNDN);
    mpfr_printf("x = %Rf\n", p);
    mpfr_div_z(p, p, y, GMP_RNDN);
    mpfr_printf("x/y = %Rf\n", p);

のように途中結果を出力するようにし、
両アイテムともに現状より6個ずつ獲得した場合

    prob(p, 24, 33);

についてみてみる。pが100ビット精度の場合、

x = 102430771061474086
x/y = 0.71075625289097947578920155820015

手元の環境のデフォルト精度(53ビット)では、

x = 102430771061474080
x/y = 0.71075625289097943

となり、この精度では二項係数の部分和xを完全には表現できなくなる。
その結果、確率の値x/yもほんの少しだけ異なってしまう。とはいえ、まだ6桁表示での違いはない。
しかし二項係数の部分和がどんどん大きくなっていけばいつかは6桁表示すら怪しくなるだろう。
もちろんそのときには100ビット精度でも十分ではなくなると思う。

さいわいにも前回示した現状のアイテム獲得数での確率

    prob(p, 18, 27);

については問題なく計算できている。このとき、

x = 26997208242192

であり、これは45ビットで表現でき、デフォルト精度で十分だからである。