- ベストアンサー
99.98+0.01の誤差
double型での計算を行うとよく誤差が出るのは知っているのですが System.out.println(99.98+0.01); といった簡単な計算ですら数値が狂うのは何故なのでしょうか?-サブ質問1 みなさんは厳密な計算が必要なときどのように処理を行っていますか?-サブ質問2 ちなみに私はできるだけdouble型は使わないことで回避しています。 処理したい有効桁数分10^n倍していってlong型で計算したのち元に戻したりと。 もっとスマートにdouble型だけで正確に計算して使っている方が いらっしゃいましたらその技を伝授していただけませんか?-メイン質問 わかる範囲でいいのでお答えをお持ちの方がいらっしゃいましたらよろしくお願いします。
- みんなの回答 (5)
- 専門家の回答
質問者が選んだベストアンサー
こんにちは >といった簡単な計算ですら数値が狂うのは何故なのでしょうか?-サブ質問1 2進数だと無限小数(循環小数)になるから、誤差が大きく出てしまうのですね。 >みなさんは厳密な計算が必要なときどのように処理を行っていますか?-サブ質問2 私は分数の概念を使って計算させています。 結局、我々が入力する数値は整数か有限小数ですよね。 それらの四則演算は有理数同士の四則演算なので、結果が整数、有限小数、循環小数のいずれかになります。 これらを正確に表そうとすると、分母と分子が整数の分数として扱うのが良いですね。 これを使うと、例えば x=1÷3 というようにxに1÷3を入れると、xは0.33333・・・と循環小数になりますが、内部的には3分の1となっているので、 x=x×3 とやると、xは1になってくれます。 >もっとスマートにdouble型だけで正確に計算して使っている方が >いらっしゃいましたらその技を伝授していただけませんか?-メイン質問 スマートには難しいですね。 分数での処理がスマートかと言われると難しいですね。
その他の回答 (4)
- notnot
- ベストアンサー率47% (4900/10358)
>ちなみに私はできるだけdouble型は使わないことで回避しています。 >処理したい有効桁数分10^n倍していってlong型で計算したのち元に戻したりと。 少しだけスマートでいうと、10^n倍したんなら整数になっているはずなのでそのままdoubleで計算しても(有効数値15桁を超えたり、整数で割り切れない割り算をしたりしない限り・・・整数計算なので当然)誤差は出ません。 数字文字列に変換するときは10^n倍したまま、いったん文字列に入れて、下からn桁目の左に小数点を割り込ませるように文字列処理すればいいと思います。
- chi-kon
- ベストアンサー率43% (58/132)
厳密というか、 そういう困ったチャンなことが起きる場合は BigDecimal使ってこちら側の意図するどおりの桁扱いをするようにしています。 めんどくさいんですけどね。
- furyfox
- ベストアンサー率56% (58/103)
doubleは8バイトの浮動小数点です。 http://www.jtw.zaq.ne.jp/kayakaya/new/kihon/text/fudo.htm >もっとスマートにdouble型だけで正確に計算して使っている方が >いらっしゃいましたらその技を伝授していただけませんか?-メイン質問 10進数に換算すると有効桁数は15桁です。 つまり16桁目以降で誤差がでる可能性があります。 double型ではそれ以上の精度の計算は「不可能」です。 計算で誤差をだしたくないなら 整数型で分母と分子を分け、 無理数や定数は別に計算するような クラスを作ってはどうでしょうか? >ちなみに私はできるだけdouble型は使わないことで回避しています。 >処理したい有効桁数分10^n倍していってlong型で計算したのち元に戻したりと。 あまり意味があるものではありません。 結局longも8バイトの整数型なのですから有効桁数に限界があります。 longの限界は9223372036854775807 1桁けずって18桁が有効桁数です。 計算速度を考えればdoubleでやったほうが圧倒的に速いですし、有効桁数が限られている以上、精度には限界があります。
- ranx
- ベストアンサー率24% (357/1463)
> System.out.println(99.98+0.01); > といった簡単な計算ですら数値が狂うのは何故なのでしょうか?-サブ質問1 2進数で計算しているからです。99.98、0.01 はいずれも2進数では無限小数になります。 それを有限なコンピュータで計算するのですから、小数点以下のどこかでぶったぎる 必要が生じます。そのための誤差です。 > みなさんは厳密な計算が必要なときどのように処理を行っていますか?-サブ質問2 何をもって厳密と考えるかにもよります。何かの測定値であれば、そもそも最初から 誤差を含んでいますから、10進数での表現と2進数の表現とでどちらが正しいとも 言えないと思います。99ドル98セントといった数値であれば、java.math.BigDecimal等を 使うかもしれません。