本日のハマリ:BigDecimal使ったのに誤差が出る
「計算結果に誤差が出ます」
「浮動小数点数を使っているのでは?」
「ちゃんとBigDecimalを使ってます」
public class Test {
private static final BigDecimal MAX_TOTAL = new BigDecimal(10000000000000001L);
public static void main(String[] args) throws Exception {
System.out.println("Value = " + MAX_TOTAL.longValue());
}
}
J2SE1.4までだとBigDecimal(long)というのは無いから、doubleに昇格されて、BigDecimal(double)が呼び出される。しかしdoubleの仮数部は53bitしかないから、この引数だと誤差が発生する。1.4迄だと結果は
Value = 10000000000000000
同じソースをJ2SE5.0でコンパイルし直した場合、BigDecimal(long)が使用されるので、誤差が発生しない。
Value = 10000000000000001
1.4までの場合は文字列バージョンを使用しないといけない。
private static final BigDecimal MAX_TOTAL = new BigDecimal("10000000000000001");
多分「53bitで表現できる範囲をこえるなら文字列で」なんて難しいコーディングルールを作っても、遵守は困難だろうから、常に文字列版を使用させるのが無難かな。チェックはBigDecimal(double)の呼び出しを見つけるディテクタ作ってFindBugsで見つけるのが簡単そう。





