はじめに
仕事で金利に関するロジックを書いた時に、JavaのBigDecimal型を使ったので、BigDecimal型の使い方についてメモすることにしました。
なぜBigDecimal型を使うのか
BigDecimalには下記のような特徴があるため、誤差・意図しない値の丸めが発生することが許されない金額の計算のようなケースでは、float, double型ではなくBigDecimalの使用が推奨されます。
1. float, double型と違って少数の計算で誤差が発生しない
BigDecimalと同様に少数を表現する型として、float型とdouble型があります。float型とdouble型は、値を2進数で保持する関係上、循環小数としてしか表現できない10進数の少数が存在するため、少数を計算する過程で値を丸める必要があり、その過程で計算結果に誤差が発生してしまいます。 その反面、BigDecimal型では、値を「整数 * 10の何乗」という形式で保存しているため、10進数の有限小数のすべてを誤差なく表現することができます。
2. 値の丸めかたを指定することができる
BigDecimal型では、値の計算をすべてメソッド経由で実施するため、値の丸めかたを指定することができます。
// 1. float, double型では、少数の計算で誤差が発生するケースがある double doubleAnswer = 3.3 / 1.1; System.out.println("double: " + doubleAnswer); // double: 2.9999999999999996 BigDecimal bigDecimalAnswer = BigDecimal.valueOf(3.3).divide(BigDecimal.valueOf(1.1)); System.out.println("bigDecimal: " + bigDecimalAnswer); // bigDecimal: 3 // 2. 値の丸めかたを指定することができる double doubleAnswer2 = 10.0 / 3.0; System.out.println("double: " + doubleAnswer2); // double: 3.3333333333333335 BigDecimal bigDecimalAnswer2 = BigDecimal.valueOf(10.0).divide(BigDecimal.valueOf(3.0), 2, RoundingMode.HALF_UP); System.out.println("bigDecimal: " + bigDecimalAnswer2); // bigDecimal: 3.33
BigDecimalの生成
数値からBigDecimalを生成するときは、valueOf
メソッドを使用し、文字列から生成する場合は、コンストラクタを使用します。
BigDecimal value1 = BigDecimal.valueOf(1234.56);// 数値からの生成 BigDecimal value2 = new BigDecimal("1234.56");// 文字列から生成
BigDecimalの定数
0
, 1
, 10
は定数として定義されています。
BigDecimal.ZERO BigDecimal.ONE BigDecimal.TEN
値の比較
equals
メソッド使用した場合、値のscaleが一致していないと、値が同一でもfalse
が出力されてしまいます。
System.out.println(BigDecimal.valueOf(0.0).equals(BigDecimal.valueOf(0))); // 値のscaleが異なるため、falseになってしまう System.out.println(BigDecimal.valueOf(0).equals(BigDecimal.valueOf(0))); // true
そのため、BigDecimalで値の比較を行う場合は、compareTo
メソッドを使用しましょう。compareTo
メソッドでは値は等しいがscaleが異なるBigDecimalオブジェクトを等しいとみなします。(例えば、2.0と2.00は等しいとみなされる)
BigDecimal one = BigDecimal.valueOf(1.00); System.out.println(one.compareTo(BigDecimal.ZERO)); // 1 System.out.println(one.compareTo(BigDecimal.ONE)); // 0 System.out.println(one.compareTo(BigDecimal.TEN)); // -1
compareTo
メソッドでは、数値がパラメーターの値よりも小さい場合は、-1
、等しい場合は0
、大きい場合は1
を返します。
加算
BigDecimal three = BigDecimal.valueOf(3.00); BigDecimal four = BigDecimal.valueOf(4.0); System.out.println(three.add(four)); // 7.0
減算
BigDecimal three = BigDecimal.valueOf(3.00); BigDecimal four = BigDecimal.valueOf(4.0); System.out.println(three.subtract(four)); // -1.0
乗算
BigDecimal three = BigDecimal.valueOf(3.00); BigDecimal four = BigDecimal.valueOf(4.0); System.out.println(three.multiply(four)); // 12.00
除算
scale
を指定せずに、divide
メソッドを使うこともできますが、割り切れないときにArithmeticException
が発生するのでscale指定版を使用するほうが無難です。
BigDecimal three = BigDecimal.valueOf(3.00); BigDecimal four = BigDecimal.valueOf(4.0); System.out.println(three.divide(four, 3, RoundingMode.HALF_UP)); // 0.750
参考サイト
BigDecimal (Java Platform SE 8)
【Java】BigDecimalをちゃんと使う~2018~ - Qiita