• ベストアンサー

丸め誤差への対処法についての疑問

丸め誤差についてですが、 浮動小数点数の内部表現は2進数である為、循環小数となる「0.1」等を含んだ計算結果は誤差が 生じる事が多く、その対策として「整数にしてから計算し、その後割り戻す」 というのをよく目にします。 例えば、javascriptで行う下記のような計算です。 (1)0.1×6=0.6000・・・01 ※誤差が出る (2)0.1×10×6=6 ※整数にしてから計算 (3)(0.1×10×6)/10=0.6 ※割り戻す この時、(2)の「0.1×10」の箇所で誤差が生じないのは何故でしょうか? 「0.1」という数字自体が2進数に変換した時既に誤差が生じているのであれば、 誤差が生じている数字に10を掛けてもやはり誤差が残ってしまう気がするのですが。 また、(3)の割り戻し処理では結果が少数となりますが、この時に誤差が生じる事はないのでしょうか?

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

  • ベストアンサー
  • venzou
  • ベストアンサー率71% (311/435)
回答No.3

(2)でも(3)でも誤差はあります。 整数化するのは、誤差の蓄積をなくし、 出来るだけ誤差を少なくするためのものです。 完全に誤差をなくすことは出来ません。 具体例を見た方が分かりやすいでしょう。 -------------------------- var x = 3.3/10; document.write("x="+x+"<br>"); // ・・・ (1) var y = Math.round(x * 100 + 0.5); // ・・・ (2) document.write("y="+y+"<br>"); var ansx = 0; var ansy = 0; for(var i = 0; i < 10000; i++){ // ・・・ (3) ansx += x; ansy += y; } ansx /= 10000; // ・・・ (4) ansy /= 1000000; // ・・・ (5) document.write("ansx="+ansx+"<br>"); // ・・・ (6) document.write("ansy="+ansy+"<br>"); // ・・・ (7) -------------------------- (1):0.32999999999999996  誤差が発生しています。  (Windows XP、IE6.0の場合、ブラウザにより多少異なるかも) (2):yはxを100倍して整数化します。  round関数で明確に整数へ変換します。(0.5を足して、四捨五入しています。)  整数に変換することにより、誤差は切り捨てられます。 (3):それぞれforループで1万回足します。 (4):xの合計を1万で割ります。  1万倍して、1万で割った事になるので、元の数に戻るはずです。 (5):yは100倍してあったので、合計を100万で割ります。 (6):0.3299999999999554  (1)と比べて、誤差が増えているのがわかります。 (7):0.33  誤差はありません。  この例で誤差が出ないだけで、  (7)でも誤差が生じる可能性はありますが、  (6)と比べると少ないものになります。 ------------------------------------- 誤差そのものは小さいものなので、 数回の計算なら整数化する必要はないでしょう。 しかし、何回も繰り返し計算をする場合、 誤差が蓄積し、大きくなる可能性があります。 そういう場合に、整数化することにより、 誤差を少なくすることが出来ます。

eri840312
質問者

お礼

具体例までご提示頂き、ありがとうございます。お手間だったのではないでしょうか? 「整数にしてから計算し、その後割り戻す」というのは、誤差をなくす為の方法ではなく 誤差を少なくする為の方法なんですね。 (2)のように、整数化した場合に誤差が出ない時は、具体例(7)のようにたまたま出ていないだけか、 誤差が小さすぎて無視されている(?)と考えるようにします。 ところで、Math.round(x * 100 + 0.5); の箇所ですが、0.5 を足してからroundで 四捨五入しているのは何故でしょうか?

その他の回答 (4)

  • venzou
  • ベストアンサー率71% (311/435)
回答No.5

#3です。 >ところで、Math.round(x * 100 + 0.5); の箇所ですが、0.5 を足してからroundで >四捨五入しているのは何故でしょうか? すいません、間違いました。 floor関数とごっちゃになっていました。 round関数の場合0.5を足す必要はありませんね。失礼しました。 Math.round(x * 100); 余談: 四捨五入用の関数が用意されていない場合、 0.5を足して切り捨てるという方法がよく使われます。 (ただし、負の数の場合に問題がある)

eri840312
質問者

お礼

お返事ありがとうございます。 勘違いだったんですね。 余談の四捨五入の話も参考になりました。

回答No.4

「割るだけ」の場合ではそのまま割ってから誤差を切り捨てや四捨五入で削除します。 割り算とかけ算の両方を行う場合は かけ算を行ってから割り算を行い、誤差を削除します。 > (2)0.1×10×6=6 ※整数にしてから計算 誤差処理をしてないので、本当は 6.0000000...1 です。 最近のブラウザはうまく処理してるので6と表示されます。*これが「6」と表示される要因。 ”安物の”電卓で 5/3*6 と 5*6/3 を比べてみてください。

eri840312
質問者

お礼

整数化して計算したから誤差は安心というわけではなく、本当は誤差が出てるんですね。 アドバイス頂いたように、切り捨てや四捨五入で対応するようにします。 ありがとうございました。 ちなみに、私の電卓では 5/3*6と5*6/3は違う結果になりました。安物?(笑)

noname#140971
noname#140971
回答No.2

(1)0.1×6=0.6000・・・01 ※誤差が出る (2)0.1×10×6=6 ※整数にしてから計算 (3)(0.1×10×6)/10=0.6 ※割り戻す ではなくて (1)0.1×6=0.6000 (2)(1×6)=6 (3)(1×10×6)/100=0.6 という話じゃないのかな。 単なる服飾デザイナですが、整数にしてから計算とか割り戻す例とすれば・・・。

eri840312
質問者

お礼

例の書き方があまり良くなかったでしょうか。 アドバイスありがとうございます。

  • SAYKA
  • ベストアンサー率34% (944/2776)
回答No.1

演算結果は環境によるけれど予測している通り(2)でも0.1そのものが誤差を持つ場合が否定できないよね。 内部的には高速化するために循環の小数の2進数かもしれなけれど実は 1x(10^(-1)) という値の保持の仕方をしていたらちょっと話が変わる。 昔は兎に角小さく、小容量にって事で小数でも完全に2進数化していただろうけれど演算精度を上げるために違う保持をしているかもしれない。 http://journal.mycom.co.jp/column/architecture/092/index.html ・・・でもやっぱり2進数みたい・・・答えにならなかったけど参考に。

eri840312
質問者

お礼

URL参考にさせて頂きました。 ありがとうございます。

関連するQ&A

  • 浮動小数点の計算について

    Javaで0.1+0.2を計算すると0.30000000000000004になったり、10.0-9.9を計算すると、0.09999999999999964になったりするのはなぜですか? 参考書では。 「浮動小数点数を使った計算では、一見正確な値が計算されてるように見えてもほとんど場合内部では少しだけ誤差を含んだ値を持ってると、考えた方がいいでしょう。どのような計算を行った時にどの程度の誤差が出るのかは難しい話題になるのでこの本では詳しく説明しませんが、例えば100.0-99.99のように同じぐらいの数同士で引き算を行うと誤差が現れやすくなります。」 と書いてありました。 この本ではこれだけで説明が終わりました。 なぜ浮動小数点で計算を行うと誤差が出るのか詳しく教えていただけると助かります。

    • ベストアンサー
    • Java
  • 少数計算の誤差について

    お世話になってます。 javascriptでの少数計算結果について、 document.write(1100 * 93.07);  ⇒102376.99999999999 document.write(1100 * 93.17);  ⇒102487 document.write(1100 * 93.57);  ⇒102926.99999999999 上記のような結果になるのですが、法則が分からず悩んでいます。 javascriptの仕様のようで、整数にしてから割り戻す方法で回避しようと考えてますが 結果に誤差がでる組み合わせの法則はどのようになっているのでしょうか? 宜しくお願いします。

  • 計算の丸め誤差の解消について

    プログラム上で計算するときに丸め誤差が発生し、困っています。 丸め誤差が発生している計算は -0.004+0.006+0.002 なのですが、 -0.004+0.006+0.002=0 となるところが、 =8.47E-09 となってしまっています。 オーダーの異なる計算ではないにもかかわらず、どうして誤差が発生するのかが理解できず困っています。 上の数値(左辺の方)の算出は、10^(-1)のオーダーの数値から計算されています。 多分、浮動小数点を使っているからだろうと考えているのですが、どのように解消したらよろしいでしょうか? 固定小数点を用いると、浮動小数点より誤差が少ないとありましたが、Cで固定小数点を用いる方法もわからないです。 よろしくお願いします。

  • 16ビット浮動小数点数の表現方法について

    学校の課題において、ある数を2進数で表現し、さらにその数を16ビット浮動小数点数で表しなさい。またそのとき生じる誤差の名称を記しなさい、という課題がでており取り組んでいるのですが、ネットで調べていても計算方法が理解できず行き詰っております。どなたか計算方法の手助けをお願いできないでしょうか。 与えられた条件 符号ビット:1ビット(0:正、1:負) 指数部:4ビット 仮数部:11ビット 16ビット浮動小数点数で表す数 10011100011000011 です。計算方法を理解したいので、なるべく詳しくお願いいたします。 誤差の名称もできればご教授願います。

  • データ型について

    VBに限ったことではないのですが、 データ型には、短整数型、整数型、長整数型、単精度浮動小数点数型、倍精度浮動小数点数型といろいろな型がありますが、 整数を扱うなら長整数型、小数も含めて扱うなら倍精度浮動小数点数型 を使えば良いと思うのですが、それにより桁数の小さな短整数型、整数型とかは何のためにあるのでしょうか? あまり大きな値を扱わないときにそちらの型を選ぶメリットは何なのでしょうか?

  • さっきの小数点切捨て→浮動小数点数の演算誤差について

    さっき、http://oshiete1.goo.ne.jp/kotaeru.php3?q=685942で切捨てがうまくできないっていう質問があって、私は計算機を出してまでなんでやろ~って思って計算して、回答しました。 ところがです、あっさりとそれは浮動小数点数の演算誤差ですっていう答えがすでに出ていたんです。(勉強になりました) うぅぅ~計算機まで出してきて計算した私ってなんてお馬鹿・・・トホホってそれはさておき ここからが質問なんですが、浮動小数点数の演算誤差っていうのはなんとなくは知っていたのですが(本で読んだことはある程度で、もちろん人に説明できるレベルではありませんが)そういうのってどんな場合にでるのでしょう。 さっきの質問の確認のため、Excel2002でオプションの計算のしかたなども変えてみてやったのですが、一度もそういう計算結果はでなかったのですよ。 でも、質問されている方がいるということはそういう計算結果もでるっていうことですよね。なので、どういう場合にそういう結果がでるのかと気になって。 さっきの質問の所に書き込もうかとも思ったのですが、他の方の質問にさらに質問するっていうのは失礼なような気もして、新しく質問しました。 先ほど答えていらっしゃった方でも、他の方でそういうことに詳しい方でもお時間あれば教えていただけないでしょうか。

  • 有理数でない数について 

    今高校一年の勉強をしているのですがわからない事が一つあります。 整数、有限小数、循環小数のいずれかであれば必ず有理数であるのは解ります。この逆(有理数であれば循環少数、有限小数、整数のいずれかである)も納得です。 ここで循環しない無限小数は上から有理数ではない、もわかります。 ここで質問なのですが有理数でないものは必ず循環しない無限小数であるといえるのでしょうか?

  • 浮動小数点数の誤差範囲を教えてください

    猿より若干頭がいい、冴えないプログラマです。 面積を計算する際は必ず誤差がないように、doubleを使わずcurrencyを使っています。 メートルなら小数点4桁で足りますが、キロメートルとなると通貨型の4桁数では足りません。 doubleを使っても、平方キロを平方センチに変換して集計しても誤差は出ないでしょうか。 実際浮動小数点数はどの程度の誤差を生むのでしょうか。猿でも分かる程度教えてください。 基礎過ぎて動物園に帰れのような批判は勘弁してください。。。

  • 浮動小数点数の誤差

    恐ろしく基本的なこと聞きます。 Public Class himajin100000 Shared Sub Main Dim foo As Double = 0.5 '2進数で表現できる Dim bar As Double = 0.1 '割り切れないから誤差が出る System.Diagnostics.Trace.WriteLine((foo - bar).ToString) '0.4 '・・・あれ?浮動小数点数の誤差どこ行った? End Sub End Class

  • β進n桁の浮動小数点

    2進3桁、ML(絶対値最大の浮動小数点数)=1 MU(絶対値最小の浮動小数点数)=2の浮動小数点数の 体系で表現できる数は全部でいくつか、すべて挙げよ。 また、計算機イプシロンを求めよ。 ・・・っという問題がわからなくて困っています。 どなたか、解法手順またはアドバイスをよろしくお願いします。

専門家に質問してみよう