LoginSignup
3
4

More than 5 years have passed since last update.

BigDecimalの使い方

Posted at

小数を扱うコードを作成していて、色々と嵌ったのでそのときのメモ。

起きたこと

小数の値を除算する必要があったので、以下のようにBigDecimalを利用して除算するコードを書いた。

public class Divide {
    public static void main(String[] args) {
        BigDecimal num1 = new BigDecimal(1.1);
        BigDecimal num2 = new BigDecimal(100);

        System.out.println(num1.divide(num2));
    }
}

1.1÷100なので、結果は0.011になるはずだが、実行してみると「0.01100000000000000088817841970012523233890533447265625」と出力される。
なんでやねん、と思ったが使い方が悪かった。

何が起きていたのか

BigDecimalを生成するときに1.1を引数にしているが、こいつがすでに誤差を含んでいるらしい。
10進数小数を2進数小数で表すため、そもそも表現できない値がある。考えてみれば当たり前だ。。。
1.1はその表現できない値であるため、それをもとにBigDecimalを生成すると、その誤差まで保持してしまう。

どうすればいいのか

以下のように、doubleやfloatの値を利用しないようにする。

public class Divide {
    public static void main(String[] args) {
        BigDecimal num1 = new BigDecimal("1.1");
        BigDecimal num2 = new BigDecimal("100");

        System.out.println(num1.divide(num2));
    }
}

こうすれば、正確な計算が行われる。
それなら、BigDecimalにdoubleを引数とするコンストラクタは必要なのか・・・?

さらに嵌ったこと

以下のように割り切れない値を計算するとArithmeticExceptionが発生する。

public class Divide {
    public static void main(String[] args) {
        BigDecimal num1 = new BigDecimal("1.1");
        BigDecimal num2 = new BigDecimal("3");

        System.out.println(num1.divide(num2));
    }
}

BigDecimalのdivideメソッドはデフォルトだと割り切れない場合、例外を発生させるらしい。
そのため、以下のように桁数と丸め方を指定して利用する。

public class Divide {
    public static void main(String[] args) {
        BigDecimal num1 = new BigDecimal("1.1");
        BigDecimal num2 = new BigDecimal("3");

        System.out.println(num1.divide(num2,2,RoundingMode.FLOOR));
    }
}
3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4