Hatena::ブログ(Diary)

じゅんいち☆かとうの技術日誌 このページをアンテナに追加 RSSフィード Twitter


はてなブログに引っ越しました。

2009-10-24

[] 小数点の計算をやるからといってすぐにfloatやdoubleを使ってはいけない

おつかれさまです。

型を選ぶというのはプログラミングの基礎中の基礎ですが、以外に開発の現場でも注意が必要なのが、floatとdoubleの精度の問題があります。これぐらい当然と思っていたのですが、最近よく耳にしますので、あえて言及w

これらの型の目的が科学技術計算のための用途。多少誤差が生じても高速に演算をすることを目的としています。グラフィックなどの描画系とかですかね。

このように、float型やdouble型は誤差を含む可能性があるため、科学・工学計算で多少の誤差は許容できる場合はよいのですが、金融・会計分野のように正確な値が要求される計算には向きません。

どうしても正確な値が欲しい場合は、BigDecimalクラスを使用することになります。基本データ型のdoubleやfloatと比較すると不便かつ低速ですが、精度が保証されており、丸め方も指定できます。

正確な値が要求される計算にfloat,double型は使えない!|情報科学を学ぶ大学生のブログ

ここで言及されているように、お金や会計などの正確性を問われる計算では使えません。基本的にBigDecimalを利用しないといけませんね。(桁数によってはintやlongを整数部と小数部に分けて演算する方法が考えられますがずばり面倒ですw←勘違いでしたw 多少演算速度が遅くともBigDecimalがよいですw)

なので、小数点を計算するからこの変数はfloatか、dobuleかなという安易な考えはよくないのです。目的に応じた型を選ぶことが重要。

たとえば、Efficetive Javaでも登場するこの式。当然これでは誤差が発生します。

System.out.println(1.00-9*.10);

私の環境でこのような結果になりました。

0.09999999999999998

次はBigDecimalの例。

ちょっとコードが面倒な感じになってきましたw

	// 1.0 - 9 * 0.1
	BigDecimal b1 = new BigDecimal(1.0);
	BigDecimal b2 = new BigDecimal(-9);
	BigDecimal b3 = new BigDecimal("0.1");
	BigDecimal result = b1.add(b2.multiply(b3));	
	System.out.println(result.toString());

でも、結果は期待どおりです。

0.1

0.1の部分だけが文字列表現ですが、これは精度が落ちないために文字列初期化しています。数値で渡すと誤差が発生するので気をつける。

BigDecimal b3 = new BigDecimal("0.1");

詳しくはこちら。

doubleからBigDecimalオブジェクトを作成する場合、

BigDecimal bd = new BigDecimal(doubleVal);

としてしまうと、浮動小数点で正確に表せない数値の場合、期待結果とズレる場合があります。

floatをもとにBigDecimalオブジェクトを作成する。 - 未来を愛すべきこと-Javaやったり技術書読んだり

小数点以下まできっちり計算しないといけない用途ではBigDecimalということで。

間違っても、floatやdoubleでお金の計算をしておいて、発生したその誤差を調整するようなロジックは書いてはいけませんよ。

追記:

Effective Java 初版 31項、第二版 48項に事例の紹介があります。

(太)(太) 2009/10/27 01:59 あれ?
もしかして八丁堀付近によくいる方ですか?

> 間違っても、floatやdoubleでお金の計算をしておいて、
> 発生したその誤差を調整するようなロジックは書いてはいけませんよ。

RoundingMode.HALF_DOWNも禁止の方向でお願いします。
5捨6入なのに、指定桁数切り捨てだと勘違いしやすいらしいです。

uehajuehaj 2009/10/28 10:21 金融系ならGroovyがお薦めです。
(1)デフォルトの浮動小数点定数(接尾辞を省略した場合)がBigDecimal
(2)BigDecimalに四則演算のためのオペレーターオーバーロード定義がなされている
ために簡潔に使うことができます。
除算オペレータはROUNDD_HALF_UP固定のようでした。

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証