BigDicimalで小数点以下を計算する方法
銀行の預金金利やモノを買うときに発生する消費税など、小数点以下の数字をあつかうITシステムは多く存在します。
それらのシステムでは1円の誤差も許されない正確な計算が必要となります。
そのような場合に使用するのがBigDecimalです。
Javaでは小数点以下を扱えるdouble/floatといった他のクラスも存在します。
ただし、double/floatは誤差が生じる可能性があります。
正確な計算が必要な場面ではBigDecimalを使用しましょう。
そして、BigDecimalでは四則演算を行う場合、”+”や”-“といった算術演算子ではなく専用のメソッドが用意されています。
メソッド | 説明 |
add() | 足し算 |
subtract() | 引き算 |
multiply() | 掛け算 |
divide() | 割り算 |
BigDecimalクラスを使用するには、以下のパッケージをインポートします。
import java.math.BigDecimal;
例えば、以下のようにインスタンスを作成して使用します。
String val = “123.456789”;
BigDecimal bd = new BigDecimal(val);
足し算
足し算を行う場合は addメソッドを使用します。
addメソッドの引数には足し合わせたい値を入れます。
戻り値は足し合わせた結果がBigDecimal型で返ります。
BigDecimalのコンストラクタの引数に浮動小数点数型と文字列型どちらも指定することができます。
しかし、引数に浮動小数点数型を指定した場合、誤差が発生するので注意が必要です。
正確な値を扱うためには、BigDecimalのコンストラクタの引数は文字列型で指定しましょう!
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
// double型で算術演算子を使う場合
double d1 = 0.8;
double d2 = 0.9;
System.out.println(d1 + " + " + d2 + " = " + (d1 + d2));
// BigDecimalコンストラクタの引数にdouble型を使用する場合
BigDecimal bd1 = new BigDecimal(0.8);
BigDecimal bd2 = new BigDecimal(0.9);
BigDecimal result1 = bd2.add(bd1);
System.out.println(bd1 + " + " + bd2 + " = " + result1);
// BigDecimalコンストラクタの引数にString型を使用する場合
BigDecimal bd3 = new BigDecimal("0.8");
BigDecimal bd4 = new BigDecimal("0.9");
BigDecimal result2 = bd4.add(bd3);
System.out.println(bd3 + " + " + bd4 + " = " + result2);
}
}
実行結果:
0.8 + 0.9 = 1.7000000000000002
0.8000000000000000444089209850062616169452667236328125 + 0.90000000000000002220446049250313080847263336181640625 = 1.70000000000000006661338147750939242541790008544921875
0.8 + 0.9 = 1.7
このサンプルコードでは、double型で算術演算子を使った場合と、BigDecimal型でコンストラクタの引数にdouble型とString型を使った場合で足し算の結果を比較しています。
double型で算術演算子を使った場合とBigDecimal型でコンストラクタの引数にdouble型を使った場合は誤差が生じて正確な値が算出できていません。
これに対して、BigDecimal型でコンストラクタの引数にString型を使った場合は誤差は生じず、正確な値を算出できています。
引き算
引き算を行う場合は subtractメソッドを使用します。
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
// double型で算術演算子を使う場合
double d1 = 1.7;
double d2 = 0.9;
System.out.println(d1 + " - " + d2 + " = " + (d1 - d2));
// BigDecimalコンストラクタの引数にdouble型を使用する場合
BigDecimal bd1 = new BigDecimal(1.7);
BigDecimal bd2 = new BigDecimal(0.9);
BigDecimal result1 = bd1.subtract(bd2);
System.out.println(bd1 + " - " + bd2 + " = " + result1);
// BigDecimalコンストラクタの引数にString型を使用する場合
BigDecimal bd3 = new BigDecimal("1.7");
BigDecimal bd4 = new BigDecimal("0.9");
BigDecimal result2 = bd3.subtract(bd4);
System.out.println(bd3 + " - " + bd4 + " = " + result2);
}
}
実行結果:
1.7 - 0.9 = 0.7999999999999999
1.6999999999999999555910790149937383830547332763671875 - 0.90000000000000002220446049250313080847263336181640625 = 0.79999999999999993338661852249060757458209991455078125
1.7 - 0.9 = 0.8
このサンプルコードでも、double型で算術演算子を使った場合とBigDecimal型でコンストラクタの引数にdouble型を使った場合は誤差が生じて正確な値が算出できていません。
これに対して、BigDecimal型でコンストラクタの引数にString型を使った場合は誤差は生じず、正確な値を算出できています。
掛け算
掛け算を行う場合は multiplyメソッドを使用します。
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
// double型で算術演算子を使う場合
double d1 = 0.8;
double d2 = 0.9;
System.out.println(d1 + " x " + d2 + " = " + (d1 * d2));
// BigDecimalコンストラクタの引数にdouble型を使用する場合
BigDecimal bd1 = new BigDecimal(0.8);
BigDecimal bd2 = new BigDecimal(0.9);
BigDecimal result1 = bd1.multiply(bd2);
System.out.println(bd1 + " x " + bd2 + " = " + result1);
// BigDecimalコンストラクタの引数にString型を使用する場合
BigDecimal bd3 = new BigDecimal("0.8");
BigDecimal bd4 = new BigDecimal("0.9");
BigDecimal result2 = bd3.multiply(bd4);
System.out.println(bd3 + " x " + bd4 + " = " + result2);
}
}
実行結果:
0.8 x 0.9 = 0.7200000000000001
0.8000000000000000444089209850062616169452667236328125 x 0.90000000000000002220446049250313080847263336181640625 = 0.720000000000000057731597280508141088104978266987413014660706603482787091508043886278755962848663330078125
0.8 x 0.9 = 0.72
このサンプルコードでも、double型で算術演算子を使った場合とBigDecimal型でコンストラクタの引数にdouble型を使った場合は誤差が生じて正確な値が算出できていません。
これに対して、BigDecimal型でコンストラクタの引数にString型を使った場合は誤差は生じず、正確な値を算出できています。
割り算
割り算を行う場合は divideメソッドを使用します。
割り算の場合は気をつけるべき点があります。
たとえば、10 ÷ 3 = 3.33333… のような結果が割り切れない値の場合、ArithmeticExceptionというエラーが発生してしまいます。
それを回避するために、BigDecimalでは各メソッドの引数に第二引数以降が用意されています。
その第3引数に計算結果の値の丸め方法を指定することで、エラーを回避できます。
ちなみに第2引数では小数点以下の桁数を指定します。
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
// double型で算術演算子を使う場合
double d1 = 10.0;
double d2 = 3.0;
System.out.println(d1 + " ÷ " + d2 + " = " + (d1 / d2));
// BigDecimalコンストラクタの引数にdouble型を使用する場合
BigDecimal bd1 = new BigDecimal(10.0);
BigDecimal bd2 = new BigDecimal(3.0);
BigDecimal result1 = bd1.divide(bd2, 1, BigDecimal.ROUND_HALF_UP);
System.out.println(bd1 + " ÷ " + bd2 + " = " + result1);
// BigDecimalコンストラクタの引数にString型を使用する場合
BigDecimal bd3 = new BigDecimal("10.0");
BigDecimal bd4 = new BigDecimal("3.0");
BigDecimal result2 = bd3.divide(bd4, 1, BigDecimal.ROUND_HALF_UP);
System.out.println(bd3 + " ÷ " + bd4 + " = " + result2);
}
}
実行結果:
10.0 ÷ 3.0 = 3.3333333333333335
10 ÷ 3 = 3.3
10.0 ÷ 3.0 = 3.3
このサンプルコードでは、double型で算術演算子を使った場合は誤差が生じて正確な値が算出できていません。
これに対して、BigDecimal型を使った場合は誤差は生じず、正確な値を算出できています。
BigDecimalで四捨五入する方法
BigDecimalで四捨五入する方法については以下の記事を参考にしてください。
【解決Java】BigDecimalで四捨五入や切り捨ての丸め誤差を解決
更新日 : 2019年4月5日
BigDecimalで消費税を計算する方法
900円の商品に対する消費税を含めた代金は 900 × 1.08 = 972円と計算ができます。
これをJavaのプログラミング上で計算をおこなう場合、double型で算術演算子を使って計算する方法と、BigDecimalクラスを使う方法があります。
import java.math.BigDecimal;
public class Main {
public static void main(String[] args) {
// double型で算術演算子を使う場合
double price = 900;
double tax = 1.08;
double result = price * tax;
System.out.println(result);
// BigDecimalコンストラクタの引数にdouble型を使用する場合
BigDecimal price1 = new BigDecimal(900);
BigDecimal tax1 = new BigDecimal(1.08);
BigDecimal result1 = price1.multiply(tax1);
System.out.println(result1);
// BigDecimalコンストラクタの引数にString型を使用する場合
BigDecimal price2 = new BigDecimal("900");
BigDecimal tax2 = new BigDecimal("1.08");
BigDecimal result2 = price2.multiply(tax2);
System.out.println(result2);
}
}
実行結果:
972.0000000000001
972.0000000000000639488462184090167284011840820312500
972.00
double型で算術演算子を使って計算した場合とBigDecimal型でコンストラクタの引数にdouble型を使った場合は誤差が発生しています。
わずかな差に見えますが、これがシステムの要件で1円以下は切り上げと決めていた場合は代金が973円となり、1円多くお客様へ請求することになります。
そして、そのことがサービスの信頼性の低下につながり、オンラインショップの場合では閉店に追い込まれる原因になる可能性もあります。
BigDecimal型でコンストラクタの引数にString型を使った場合、正確な計算結果が得られています。
BigDecimalの使い方総まとめ記事はこちら
BigDecimalのさまざまな使い方についてはこちらで詳しく解説しているので、ぜひ確認してください!
【Java入門】BigDecimalの使い方総まとめ(足し算、引き算などの計算)
更新日 : 2019年3月29日
演算子(算術演算子)について知りたい方へ
算術演算子についてはこちらで詳しく解説しているので、ぜひ確認してください!
【Javaの演算子】種類や使い方を網羅しました!
更新日 : 2018年10月4日
日付の計算について詳しく知りたい方へ
また、日付の計算についても算術演算子を使うのではなく、メソッドが用意されています。
日付の計算についてはこちらで詳しく解説しているので、ぜひ確認してください!
【Java入門】Dateクラスで現在日時の取得と加算/減算などの計算(add)
更新日 : 2019年5月22日
まとめ
ここでは、BigDecimalについて、基本的な使い方から消費税を計算する実務的な具体例についても紹介しました。
小数点以下の数字を扱うシステムは数多く存在します。
一見すると計算結果に問題ないように見えても、正確な計算が必要な場合にはdouble/floatではなく、BigDecimalを使うようにしてください。
もし、BigDecimalの使い方を忘れてしまったら、この記事を思い出してくださいね!