みんなの「教えて(疑問・質問)」にみんなで「答える」Q&Aコミュニティ

こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

浮動小数点演算でのエラー

下記のようなスクリプトを実行したところ
計算結果がうまく表現されてません。
####スクリプトの中身(tmp.plx)####
#!/usr/local/bin/perl -w
use strict ;
my $x = 38.475 ;
foreach ( 0..21 ){
$x += 0.495 ;
print $x . "\n" ;
}
####実行結果####
tmp.plx
38.97
39.465
39.96
40.455
40.95
41.445
41.94
42.435
42.93
43.425
43.92
44.415
44.91
45.405
45.9
46.395
46.89
47.385
47.88
48.375
48.8699999999999 #<=ここで本来48.87
49.3649999999999
#######ここまで
期待値が48.87と出て欲しいところ
上記のような結果となります。

2進数での計算が浮動小数点を完全に表現することができない
ことはわかるのですが、
$a=48.375;
$a+=+0.495 ;
print $a . "\n" ; # 48.87を表示
と単体での計算が正しい結果が出るのが理解できません。
どうしてなのでしょうか?

投稿日時 - 2007-04-13 23:44:43

QNo.2919120

暇なときに回答ください

質問者が選んだベストアンサー

0.495という数値は、実際にはたぶん0.495よりもごくわずかに
小さな値としてコンピュータは記憶しているのでありましょう。
例えば0.49499999999999999あたりのように。
くだんのループの終盤に来るまでは、そのわずかな誤差の累積が
計算結果に影響を与えるほどではなかったのだと思います。
ところが、ループの終盤、誤差の累積が計算結果に影響を与えるほど
大きくなり、最後の2行のようになったのだと思います。

投稿日時 - 2007-04-13 23:56:16

お礼

なるほど、納得です。
ありがとうございました。

投稿日時 - 2007-04-15 00:03:22

このQ&Aは役に立ちましたか?

0人が「このQ&Aが役に立った」と投票しています

回答(2)

ANo.2

#1の方の回答ですんじゃってますが補足として。

> $a=48.375;
> $a+=+0.495 ;
> print $a . "\n" ; # 48.87を表示
> と単体での計算が正しい結果が出るのが理解できません。

これは、二進による内部表現から十進表記に変換するときに使用している
書式の影響による丸めのために、一見正しい値になっているように見えているだけです。

C:\home>perl -d -e0

Loading DB routines from perl5db.pl version 1.28
Editor support available.

Enter h or `h h' for help, or `perldoc perldebug' for more help.

main::(-e:1): 0

DB<1> $x = 48.375


DB<2> print $x+0.495
48.87

DB<3> printf "%20.18f", $x+0.495
48.869999999999997000

DB<4>

DB<3>の出力にあるように、内部的には 48.87 という値にはなっていないのです。

投稿日時 - 2007-04-14 03:09:34

お礼

解説ありがとうございます。
たまたま浮動小数点計算でうまくいかなくなったことが
とても勉強になりました。

投稿日時 - 2007-04-15 00:05:21

あなたにオススメの質問