• ベストアンサー

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

下記のようなスクリプトを実行したところ 計算結果がうまく表現されてません。 ####スクリプトの中身(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を表示 と単体での計算が正しい結果が出るのが理解できません。 どうしてなのでしょうか?

  • Perl
  • 回答数2
  • ありがとう数2

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

  • ベストアンサー
noname#26652
noname#26652
回答No.1

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

renkado
質問者

お礼

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

その他の回答 (1)

  • sakusaker7
  • ベストアンサー率62% (800/1280)
回答No.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 という値にはなっていないのです。

renkado
質問者

お礼

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

関連するQ&A

  • 浮動小数点表現

    2^{24}を32bit整数表現及び32bit(単精度)浮動小数点表現で表せ。 結果は16進数で示せ。 符号ビット:MSB 指数部n:7ビット 仮数部:24ビット という問題があるのですが、 解いてみたものの、答えもないのであっているのか分かりません。 以下の答えで合っているでしょうか? また、合っていなかったら、どのように解くのか教えていただけませんか? 整数表現 0100 0000H 浮動小数点 0100 1000 0100 0000 0000 0000 0000 0000

  • 浮動小数点表現

    浮動小数点表現の問題で以下の実行結果を元にfloat型変数 f に与えた実数の実際に格納されているビット列を表示するプログラムを作りたいのですが、 #include<stdio.h> main() { float a; scanf("%f",&a); printf("%f",a); } この程度までしか作れません。ポインタを使ってアドレスを表示することは分るのですが…。 どなたか教えていただけると助かります。 実行結果 Size of Float : 4 byte Size of Int : 4 byte f=0.500000000000000 00111111000000000000000000000000

  • join と split で文字列を操作する場合

    にんにちは、 うまく解決する方法を思いつかないので、質問させてください。 以下のスクリプトを実行すると、a から z を * で join して、 その後、* で split するかなと思ったら、split は正規表現として とらえるためでしょうか、エラーになります。 #! /usr/bin/perl -w use strict; my $a = '*'; my $b = join $a , ('a'..'z'); print "$b\n"; my @result = split /$a/,$b; print "$_\n" foreach @result; exit(); $a = '\*'; にすると、split したときに、 余計な \ が残ってしまいます。 任意の(書く時点では分からない)いろんな文字列で 連結したり分割したりする場合のスマートな方法が ありましたら、教えていただけませんか? Perl 5.8 です。お願いします。

    • ベストアンサー
    • Perl
  • 文字列連結演算子と浮動小数点型

    本に 「文字列型連結演算子では浮動小数点型等の出力形式を指定できません。出力をフォーマットしたい場合はprintf関数を利用する」 と記載されていますが、これ以上の詳しい説明が記載されていないので、それがちょっと分かりません。分かる方は教えてください。 私の仮定では、 --------------------------------------------- <?php $a=1.23; $b=1.23; print $a.$b //文字列連結演算子で$aと$bを繋ぐ。 ?> --------------------------------------------- 出力結果は1.231.23となる。それを回避するために --------------------------------------------- <?php $a=1.23; $b=1.23; printf("%f",$a.$b) //printf関数を使って出力をフォーマット ?> --------------------------------------------- 出力結果は1.231000となりますが、その解釈で正しいでしょうか。

    • ベストアンサー
    • PHP
  • 見えない浮動小数点演算誤差?

    二つのBOOKにある表のデータの数値をVBAで比較していました。 単に各セルのValueとValueが等価かどうか=で比較しただけです。 すると見た目(表示)も数式バー上の値もまったく同じなのに相違があると判定されました。 不思議に思い、二つのBOOKにある表のデータの数値のうち違いがあると出た2つのセルを、そのまま別シートにコピー貼り付けして比較したのが添付の図です。 たとえば、BOOK-AからコピペしたB3セルの値は0.669です。 BOOK-BからコピペしたC3セルの値も0.669です。 両方とも数式バーでみましたが、間違いなく0.669です。 A3セルに =B3=C3 と入れるとTRUEが返ります。 ところが、D3セルに =B3-C3=0 と入れるとFALSEが返ります。 では、0でないなら差額はいくら?と、B11セルに=B3-C3と入れると、0が返ります。 これまで浮動小数点演算誤差で、見た目がおなじでも小数点以下かなり下の方で違いケースは経験していましたが、その場合でも小数点以下の表示を20位くらいまで表示させると違いが表れました。ところが今回は誤差が見えません。 差額確認のためVBAで Sub test01() Debug.Print Range("B3").Value = Range("C3").Value Debug.Print Range("B3").Value - Range("C3").Value Debug.Print Range("B5").Value = Range("C5").Value Debug.Print Range("B5").Value - Range("C5").Value End Sub としてみると、 False 1.11022302462516E-16 False 1.11022302462516E-16 が返りました。 エクセル2010と2016の2つで試しましたが同じ結果でした。 こんなことってあるんでしょうか? 困惑しています。

  • 繰り返し文における小数の挙動

    以下のような簡単なプログラムを書いて実行させたところ、小数点表示の挙動がおかしくなりました。 ###プログラム ここから #!/usr/bin/perl use strict; use warnings; for(my $i=0.01;$i<=1;$i+=0.001) { print $i,"\n"; } ###ここまで ##結果 ここから . . . 0.685 0.686 0.687 0.688000000000001 0.689000000000001 0.690000000000001 ##ここまで 以上のように、0.001づつ増加する $i に途中から000000000001が加わってしまいます。この000000000001が足される現象をやめさせたいです。原因、解決策等おわかりであれば教えていただけないでしょうか。よろしくお願いします。

    • ベストアンサー
    • Perl
  • requireについて教えてください。

    こんにちは、require について教えてください。 require されるファイルの最終行は 1 を書くのが一般的ですが、 他の値を書くと何か問題があるのでしょうか? 以下の実験をしてみました。 -- require されるファイル array.pl -- #! usr/bin/perl -w use strinct; ['a','b','c',] -- 実行するスクリプト -- #! /usr/bin/perl use strict; my $array_ref = get_array_ref('array.pl'); print "$_n" foreach ( @{$array_ref} ); exit(); sub get_array_ref {   return eval {require $_[0]}; } -- 結果 -- a b c 結果はうまく行ったのですが、eval も含めてこの様な使い方は 間違っていませんでしょうか? よろしくお願いします。

  • サーバーエラーについて

    次のプログラムを入力してみました #!/usr/bin/perl use strict; use warnings; print "Content-type: text/html\n\n”; print "Hello World!"; 実行したらInternal Sever Errorが表示されました。 プロバイダのアップロードするときのホームページサーバがwww7a.biglobe.ne.jpからftps.biglobe.ne.jpに変更しました。

    • ベストアンサー
    • Perl
  • use strictが効かない (PERL)

    たびたびお世話になっております。 PERL version 5.14.2 をWindows 7 のコマンドプロンプトから起動して使っています。 use strict; と一行目に書くと 宣言されていない変数があれば拒絶されるとのことで #!/usr/bin/perl use strict; use warnings; $a = 10; print "$a\n"; というスクリプトを書きました。が、すんなり動いてしまいます。 use strict; は どうすればうまく効くのでしょうか。 ご指導お願いします。

    • ベストアンサー
    • Perl
  • C言語による浮動小数点表示

    #include<stdio.h> #include<math.h> main() { float a=1.5*pow(2,-15); unsigned char *e; e=(unsigned char *)&a; printf("a=%02x,%02x,%02x,%02x\n",*(e+3),*(e+2),*(e+1),*(e+0)); } というプログラムで a=38,40,00,00 という結果がでたのですが これは何を表しているのでしょうか? よろしくおねがいします

専門家に質問してみよう