名無しです。
最初に質問を読んだとき、この問題に対する答え(解法)は固定小
数点しかなく、自分で小数点位置を意識してコーディングするか、
固定小数点クラスを導入すべきだと思いました。なので bignum を
使う話が出たとき、それは浮動小数点の精度を上げているだけで、
0.1 ≠ 1/10 なんじゃないかと思ったのです。
ところが、
>有効桁数の指定については bignum であれば、a で指定します。
という説明を読んで「そんなオプションがあるのか」とモジュール
の説明を読んだところ、bignum が内部で使っている Math::BigInt
の説明には、
>The actual numbers are stored as unsigned big integers
という記述がありました。固定小数点ってことですね。
bignum は a(accuracy:確度)で有効桁数を、p(precision:精度
)で小数点位置を指定するようです。
今回の問題では 1053.59 がいちばん細かい値ですから、小数点以下
2桁まで正しく扱うという意味で p に -2 を指定すれば良いでしょ
う。a のデフォルトは 40 ということなので、これで整数部が 38
桁、小数部が 2 桁の範囲の数値であれば浮動小数点の量子化誤差な
で計算ができるはずです(ほんまかいな)。もちろん、計算の途中
で 1 を 3 で割るようなことをしていないかチェックは必要ですが
(1 を 4 や 10 で割るのは結果が小数点以下2桁の範囲に収まるの
で ok)。
ということで、先のスクリプトをなおすと:
[スクリプト]
use bignum p => -2; # 小数点以下二桁
my $a = 200.00;
my $b = 1053.59;
my $c = $a * $b; #=> 21078
my $d = int($c); #=> 21n78
my $e = $c - $d;
printf("a = %+24.15lf (%s)\n", $a, $a);
printf("b = %+24.15lf (%s)\n", $b, $b);
printf("c = %+24.15lf (%s)\n", $c, $c);
printf("d = %+24.15lf (%s)\n", $d, $d);
printf("e = %+24.15lf (%s)\n", $e, $e);
[実行結果]
D:$ perl gomi.pl
a = +200.000000000000000 (200)
b = +1053.589999999999900 (1053.59)
c = +210718.000000000000000 (210718.00)
d = +210718.000000000000000 (210718)
e = +0.000000000000000 (0.00)
D:$
1053.59 が 1053.58999... と表示されたのは %+24.15lf という書
式指定のために bignum オブジェクトがただの浮動小数点数に変換
されたのが原因で、内部で保持している値は厳密に 1053.58 なのだ
ろうと推測します。
どうでしょ。間違ってたら誰か教えてください。
--