アプリ版:「スタンプのみでお礼する」機能のリリースについて

プログラム上で計算するときに丸め誤差が発生し、困っています。

丸め誤差が発生している計算は
-0.004+0.006+0.002
なのですが、
-0.004+0.006+0.002=0
となるところが、 =8.47E-09
となってしまっています。
オーダーの異なる計算ではないにもかかわらず、どうして誤差が発生するのかが理解できず困っています。
上の数値(左辺の方)の算出は、10^(-1)のオーダーの数値から計算されています。

多分、浮動小数点を使っているからだろうと考えているのですが、どのように解消したらよろしいでしょうか?

固定小数点を用いると、浮動小数点より誤差が少ないとありましたが、Cで固定小数点を用いる方法もわからないです。

よろしくお願いします。

A 回答 (6件)

コンピュータは2進数なので仕方がないです。


10進数では有限小数であっても、2進数に変換すると循環小数等になってしまい、正確に計算することはできません。
試しに0.1を2進数に変換してみると一目瞭然。

これはC言語やそのほか多くのプログラミング言語の制限事項です。
COBOLとかではきちんと計算できます。(だから昔から小数をきちんと計算する必要のある銀行系のシステムにCOBOLが多いのです。)

数値を文字列として読み込んで、計算ロジックは自作するのが一番簡単です。
    • good
    • 1
この回答へのお礼

確かに、基数変換をしてみると、0.1は2進数で表せませんでした。

このような制限があるとは知らず、プログラミングしていたので、それを解消する、また別の方法を再考します。

回答ありがとうございます。

お礼日時:2009/09/22 17:04

命題の真偽について


「浮動小数点は最後の数が0もしくは5で終わる数値以外は常に誤差が生じます」
0は間違いとして
5で終わる数値以外は常に誤差が生じます
という命題が真でもその裏命題の
5で終わる数値は常に誤差が生じない
が成り立たつとは限りませんよ
0.05に誤差があっても本命題には違反しません
    • good
    • 0

「上の数値(左辺の方)の算出は、10^(-1)のオーダーの数値から計算されています。


というのはどういう意味でしょうか? 本当にそうなら, この数値が得られた時点で (ある程度) 桁落ちは避けられないと思うのですが.
実際問題として浮動小数を使う限りこのような誤差の発生は避けられないし, 「誤差が発生する」ことは前提にしないとダメ.
    • good
    • 0
この回答へのお礼

解析を行うためのプログラミングをしているのですが、解析を行う前の準備段階での誤差でしたので、解消を考えてました。

浮動小数点を用いる限り丸め誤差を避けられないのは仕方のないことだとは思うのですが、どうしても誤差を避けたく思っていました。
この誤差の評価も含めて、解析したいと考えています。

回答ありがとうございました。

お礼日時:2009/09/22 17:10

【補足依頼】


質問者さんに確認したいことがあります。
 「-0.004+0.006+0.002」は0.004になると思いますが実際にはどんなソースコードで計算されていますか?ソース開示出来る場合は開示をお願いします。
 あと質問にある「オーダー」というのは基数とか小数点の位置を言っているのでしょうか,すいません補足説明が可能であればお教え下さい。
【アドバイス】
 小数の桁数が3桁くらいなら,回答者#1さんの回答にある整数計算というのでこの計算はできます。
 -0.004は1000倍して-4,0.006は1000倍して6,0.002は1000倍して2
あとは整数の足し算 -4+6+2=4
最後に小数に戻すために足し算した値を1000で割り0.004と答えが出ます。
 この方法の問題点は(小数を含む値 × 10^小数桁数)が整数型に収まる必要があります。また,その値を使った計算もオーバーフローしない事が条件となります。

この回答への補足

すみません。
ミスで、

-0.004+0.006-0.002

の間違いです。

補足日時:2009/09/22 16:52
    • good
    • 0

5で終わらなければ必ず誤差があるといいたかったのでしょう


対偶は誤差のないのは5で終わるですね
    • good
    • 0

浮動小数点は最後の数が0もしくは5で終わる数値以外は常に誤差が生じます



0.625だと誤差はないのですが
0.63だと浮動小数点では誤差が生じます

Cで固定小数点(10進ライブラリ)を扱えなくはないのですが
(そういうライブラリを手に入れる必要あり)
計算が非常に面倒です
(以下、あくまでも例です)

例)
 decimal a;
 a = toDecimal(0.630);
 decimal b;
 b = toDecimal(0.12);
 decimal c;
 c = addDecimal(a, b);

同様の事がC++であれば、クラスを使えるので
だいぶ簡単になります
(こちらもライブラリを手に入れる必要あり)
 decimal a = 0.630;
decimal b = 0.12;
decimal c = a+b;

で、結論ですが、そもそもどんな計算をしたいのかがわからないので
勝手に推測して答えます
1.ゲームを作成する等で計算したい
  そもそも誤差が出るのを考慮して計算する必要がある
  if (a == 0.12)は駄目で、
  if (abs(a-0.12) < 0.0001)のようにする
2.金額の計算に使う
  小数点はやめて、整数で計算すべき
  (金利などで小数が必要であれば、値を100倍、1000倍などして計算する等)
    • good
    • 0
この回答へのお礼

有限要素解析を行う場合の、有限要素行列作成のために計算される必要がある定数に関しての計算において、このような誤差が発生しました。

解析的に計算される値に対して、丸め誤差の発生を承知して解析を行うことに対して、かなり抵抗感があり、ここでの誤差を解消できるかを考えていました。

計算コストはできるだけ減らしたいのこともあり、丸め誤差の発生については再考します。

お礼日時:2009/09/22 17:00

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!