- ベストアンサー
計算の丸め誤差の解消について
プログラム上で計算するときに丸め誤差が発生し、困っています。 丸め誤差が発生している計算は -0.004+0.006+0.002 なのですが、 -0.004+0.006+0.002=0 となるところが、 =8.47E-09 となってしまっています。 オーダーの異なる計算ではないにもかかわらず、どうして誤差が発生するのかが理解できず困っています。 上の数値(左辺の方)の算出は、10^(-1)のオーダーの数値から計算されています。 多分、浮動小数点を使っているからだろうと考えているのですが、どのように解消したらよろしいでしょうか? 固定小数点を用いると、浮動小数点より誤差が少ないとありましたが、Cで固定小数点を用いる方法もわからないです。 よろしくお願いします。
- kopanda116
- お礼率43% (56/129)
- C・C++・C#
- 回答数6
- ありがとう数4
- みんなの回答 (6)
- 専門家の回答
質問者が選んだベストアンサー
コンピュータは2進数なので仕方がないです。 10進数では有限小数であっても、2進数に変換すると循環小数等になってしまい、正確に計算することはできません。 試しに0.1を2進数に変換してみると一目瞭然。 これはC言語やそのほか多くのプログラミング言語の制限事項です。 COBOLとかではきちんと計算できます。(だから昔から小数をきちんと計算する必要のある銀行系のシステムにCOBOLが多いのです。) 数値を文字列として読み込んで、計算ロジックは自作するのが一番簡単です。
その他の回答 (5)
- php504
- ベストアンサー率42% (926/2160)
命題の真偽について 「浮動小数点は最後の数が0もしくは5で終わる数値以外は常に誤差が生じます」 0は間違いとして 5で終わる数値以外は常に誤差が生じます という命題が真でもその裏命題の 5で終わる数値は常に誤差が生じない が成り立たつとは限りませんよ 0.05に誤差があっても本命題には違反しません
- Tacosan
- ベストアンサー率23% (3656/15482)
「上の数値(左辺の方)の算出は、10^(-1)のオーダーの数値から計算されています。」 というのはどういう意味でしょうか? 本当にそうなら, この数値が得られた時点で (ある程度) 桁落ちは避けられないと思うのですが. 実際問題として浮動小数を使う限りこのような誤差の発生は避けられないし, 「誤差が発生する」ことは前提にしないとダメ.
お礼
解析を行うためのプログラミングをしているのですが、解析を行う前の準備段階での誤差でしたので、解消を考えてました。 浮動小数点を用いる限り丸め誤差を避けられないのは仕方のないことだとは思うのですが、どうしても誤差を避けたく思っていました。 この誤差の評価も含めて、解析したいと考えています。 回答ありがとうございました。
- goosyu
- ベストアンサー率58% (36/62)
【補足依頼】 質問者さんに確認したいことがあります。 「-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 の間違いです。
- php504
- ベストアンサー率42% (926/2160)
5で終わらなければ必ず誤差があるといいたかったのでしょう 対偶は誤差のないのは5で終わるですね
- gau_puzzler
- ベストアンサー率48% (39/81)
浮動小数点は最後の数が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倍などして計算する等)
お礼
有限要素解析を行う場合の、有限要素行列作成のために計算される必要がある定数に関しての計算において、このような誤差が発生しました。 解析的に計算される値に対して、丸め誤差の発生を承知して解析を行うことに対して、かなり抵抗感があり、ここでの誤差を解消できるかを考えていました。 計算コストはできるだけ減らしたいのこともあり、丸め誤差の発生については再考します。
関連するQ&A
- エクセル浮動小数点演算誤差?が見えない
エクセル2010です。 BOOK-AのシートBのE7セルに0.822という数値が入っています。 見た目も、数式バー上も0.822です。 BOOK-BのシートCのE7セルにも0.822という数値が入っています。 見た目も、数式バー上も0.822です。 ところがこれを =[B.xlsm]Sheet1!E7=E7 で比較すると、falseが返ります。 これまで浮動小数点演算誤差で、見た目がおなじでも小数点以下かなり下の方で違いケースは経験していましたが、その場合でも小数点以下の表示を20位くらいまで表示させると違いが表れました。ところが今回は小数点以下30位まで表示させても0.822000000000000000000000000000で誤差が見えません。でもfalseになります。 こんなことってあるんでしょうか?
- ベストアンサー
- Excel(エクセル)
- 浮動小数点の計算について
Javaで0.1+0.2を計算すると0.30000000000000004になったり、10.0-9.9を計算すると、0.09999999999999964になったりするのはなぜですか? 参考書では。 「浮動小数点数を使った計算では、一見正確な値が計算されてるように見えてもほとんど場合内部では少しだけ誤差を含んだ値を持ってると、考えた方がいいでしょう。どのような計算を行った時にどの程度の誤差が出るのかは難しい話題になるのでこの本では詳しく説明しませんが、例えば100.0-99.99のように同じぐらいの数同士で引き算を行うと誤差が現れやすくなります。」 と書いてありました。 この本ではこれだけで説明が終わりました。 なぜ浮動小数点で計算を行うと誤差が出るのか詳しく教えていただけると助かります。
- ベストアンサー
- Java
- 数値計算における誤差について
小数点以下5~6桁の数値(整数部は1~5桁)を何度も積算するプログラムをSolaris7とWinXPで動作させたところ、同一データを使ったにもかかわらず誤差が生じました。非常に小さい差(0.2%程度)のものなので実用上は大きな問題はないのですが、何が原因でこうなるのでしょうか。プログラムでは数値を単精度として扱っています。
- ベストアンサー
- その他(OS)
- 浮動小数点演算と固定小数点演算の使い分けについて
解説書などには、「浮動小数点は3.14E0の形」や「固定小数点は3.14」などと説明されています。 では、例えば、ごく一般的な32ビットマシンで「3.14 * 45.6」という命令を書いたときに演算されるのは浮動小数点演算なのか、固定小数点演算なのかがわかりません。例えばIntelのx86CPUは、内部にFPUを持っているそうですが、この場合は「3.14 * 45.6」は、内部では必ず浮動小数点演算になっているということなのでしょうか? 「3.14 * 45.6」を「3.14E0 * 4.56E1」と書いた場合にしか浮動小数点演算されないということではないと思っているのですが、実際の浮動小数点演算と固定小数点演算の内部的な切り替えがわかりません。 理解が足りなくて、おかしな質問になっていましたら、その点もご指摘いただければうれしいです。
- ベストアンサー
- その他([技術者向] コンピューター)
- dounle型で計算時の誤差
今、VC++(MFC)で、15桁の数値まで表示可能な電卓アプリを作成しています。 そこで今つまずいているのが、double型で計算したとき(演算結果が小数の場合)の誤差の問題です。 とりあえず、いろいろなHPなどの情報を見たりして、誤差問題解決を下記のようにしました。 「数値の頭(左側)から16桁目を四捨五入する」 小数の場合はほとんど誤差が生じるため、計算後、計算結果が小数ならば、必ず 上記の誤差処理を行っています。 しかしこれでは、以下の場合に不具合が出てしまいます。 ・ 0.99 999 999 999 999 ÷ 10 = 本来の答えは「0.09 999 999 999 999 9」 ⇒ しかし15桁までの表示なので、本来は「0.09 999 999 999 999」と15桁まで出力 させなくてはいけないのに、16桁目の「9」を四捨五入したせいで「0.1」という表示に なってしまう。 16桁目を四捨五入しないと誤差をとることはできないし、でも上記の例だと正しい結果 が出力されません。 どうしたらいいのか頭を悩ませています。 何か良い解決法等あれば、ご教授お願いします!!
- ベストアンサー
- C・C++・C#
- 丸め誤差への対処法についての疑問
丸め誤差についてですが、 浮動小数点数の内部表現は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)の割り戻し処理では結果が少数となりますが、この時に誤差が生じる事はないのでしょうか?
- ベストアンサー
- JavaScript
- 浮動小数点 を整数に変えて計算する方法
floating point (浮動小数点)を integer (整数)(fixed point(固定小数点)?)にかえて計算する方法を教えてください。 よろしくお願いします。
- ベストアンサー
- 数学・算数
- 消費税計算の切り捨てによる誤差
受注金額や発注金額をDBから読み込み、税抜および税込の金額を算出するプログラムを作成しています。 税込金額を算出する際は金額+floor(金額*税率)の式を用いているのですが、 消費税分が整数になる場合、floor計算後に金額が1足らなくなることがあります。 桁上がりしない程度の数を足せばいいと言われたのですが、税率8%計算でギリギリ繰り上がらない0.039を足しても、2500万前後で誤差が発生してしまいます。 扱う金額は現在DBにある中では最大で4000万を越えます。 どうにか誤差が発生しないようにできないでしょうか?
- ベストアンサー
- MySQL
- 浮動小数点数の誤差範囲を教えてください
猿より若干頭がいい、冴えないプログラマです。 面積を計算する際は必ず誤差がないように、doubleを使わずcurrencyを使っています。 メートルなら小数点4桁で足りますが、キロメートルとなると通貨型の4桁数では足りません。 doubleを使っても、平方キロを平方センチに変換して集計しても誤差は出ないでしょうか。 実際浮動小数点数はどの程度の誤差を生むのでしょうか。猿でも分かる程度教えてください。 基礎過ぎて動物園に帰れのような批判は勘弁してください。。。
- ベストアンサー
- その他(プログラミング・開発)
お礼
確かに、基数変換をしてみると、0.1は2進数で表せませんでした。 このような制限があるとは知らず、プログラミングしていたので、それを解消する、また別の方法を再考します。 回答ありがとうございます。