On Sat, 8 Oct 2005 14:16:21 +0900 (JST)
qwerty25jp@... (TM) さんwrote:
> 初めまして、最近良くPerlを使っていますが、数値計算結果をINT関数で
> 少数点以下を切り捨てると、マイナス1となる問題が起きています。
int関数は小数点以下を切り捨てるので当然の結果ではあるのです。int関数を
使う必要はないということになります。Perlは適当に丸めて表示してくれるので、
そのまま$cを使えば、"ほぼ"期待している数値を表示してくれるのです。
これはコンピュータ(2進法で数値を表現するために)にとっては奥が深い問題
で(C言語によるアルゴリズム辞典の「四捨五入」の項を参照するとわかりやすい)、
Perlクックブックでも、「財務計算や核ミサイルなど、きわめて繊細な問題を取
り扱うプログラマは、コンピュータに組み込まれているロジックに頼るのではな
く、自分で丸め演算用の関数を実装します(数値解析についての参考書を読むこ
とをお薦めします)。」とレシピ2.2「浮動小数点数を丸める」の最後に書かれて
います。
> どの様な計算が行われているか、確認するプログラムで調べたところ、
> 浮動小数点らしい計算が行われ、結果端数が出ているためでした。
>
> $a = 200;
> $b = 1053.5900;
>
> $c = $a * $b;
>
> $d = int($c);
>
> $e = $c - $d;
>
> print " $c : $d : $e \n";
>
> 210718 : 210717 : 0.999999999970896
>
> 金額計算なのでマイナス1でも、許されない状況です。
> このような端数が出ない方法は、どの様な書き方をすれば、
> よろしいでしょうか。何方かお教え下さい。
printfやsprintf関数について調べるとよいでしょう。10進整数を使うと有効
桁は9桁ぐらいしかありません。大きい桁の整数は浮動小数点のコンパクト形式
を使って表示させるのが便利だと思います。しかし、上記のような問題があるこ
とを、"きわめて繊細な問題を取り扱う場合は"意識して、自己責任で常にチェッ
クしながら使う必要があるでしょう。次のようなスクリプトを動かしてみると数
値の背景にはいろいろと問題があることがわかるでしょう。
$a = 200;
$b = 1053.5900;
$c = $a * $b;
$d = int($c);
$e = $c - $d;
$ec = sprintf "%f.", $c;
$ed = sprintf "%f.", $d;
$f = $ec - $ed;
print "\$c = ", $c,"\n";
printf "\$c = %.15f\n", $c;
printf "\$c = %f (固定小数点形式): %g (コンパクト形式)\n", $c, $c;
printf "\$d = %f (固定小数点形式): %g (コンパクト形式)\n", $d, $d;
print "\$e = ",$e,"\n";
printf "\$e = %.15f\n", $e;
printf "\$e = %f (固定小数点形式): %g (コンパクト形式)\n", $e, $e;
print "\$f = ", $f,"\n";
printf "\$f = %.15f\n", $f;
printf "\$f = %f (固定小数点形式): %g (コンパクト形式)\n", $f, $f;
藤岡 和夫
kazuf@...
TS Networkのために http://homepage1.nifty.com/kazuf/