こんにちは。たいら(@tairaengineer2)です。
この記事でJavaのBigDecimal の解説記事です。
スポンサーリンク
- 前提条件:eclipseの環境
- BigDecimalとは
- BigDecimalが使われる場面
- BigDecimalの生成の仕方
- BigDecimalの計算の仕方
- BigDecimalの丸め方
- BigDecimalで色々な丸め方を使ってみる
- まとめ
前提条件:eclipseの環境
この記事では、eclipseのバージョンは
バージョン | Eclipse4.7 Oxygen |
---|
を使っています。
インストールの仕方は、下の記事をご参考ください。
eclipseでのJavaプロジェクト作成方法は、以下の記事をご参考ください。
eclipseでのJavaファイル作成方法は、以下の記事をご参考ください。
BigDecimalとは
変更が不可能な、任意精度の符号付き10進数です。
BigDecimalは、任意精度のスケールなしの整数値と、32ビット整数のスケールで構成されます。
0または正の場合、スケールは小数点以下の桁数です。
負の場合、スケールなしの数値に、スケールの正負を逆にした値を指数とする10の累乗を乗算します。
つまり、BigDecimalで表される数値は(unscaledValue×10-scale)です。
BigDecimal (Java Platform SE 8)から引用させて頂きました
BigDecimalは、double型やint型と同じく数字を扱う時に使います。
使う時は
import java.math.BigDecimal;
をimportして、使います。
BigDecimalを使う時はかなり限られます。
それは、数値計算はdouble型、float型どちらかを使えば賄えるからです。
では、BigDecimalを使う時はどんな時でしょうか?
次章で説明します。
BigDecimalが使われる場面
数字を扱うとき、通常の計算ならばint型やdouble型で十分です。
BigDecimal型を使うときは、正確に計算する必要があるときです。
たとえば銀行の金額計算など、誤差が許されないときによく使われます。
たとえば、1÷3のような無限小数の場合、double型で計算すると誤差が生まれます。
それはdouble型が勝手に丸めたり、桁数を区切ってしまうからです。
が、BigDecimalで計算するとあなたが
- 小数点以下の桁数
- 丸め方
を指定できるので、誤差が生まれないというわけです。
BigDecimalの生成の仕方
BigDecimalを生成するとき、valueOfメソッドを使います。
valueOfメソッドには引数の数と、引数の型で3パターンあります。
パターンは
- 引数が1つでdouble型
- 引数が1つでlong型
- 引数が2つでlong型とint型
それぞれ解説します。
パターンその1:引数が1つでdouble型
public static BigDecimal valueOf(double val)
Double.toString(double)メソッドで提供されるdoubleの正規の文字列表現を使用して、doubleをBigDecimalに変換します。
BigDecimal (Java Platform SE 8)から引用させて頂きました
使い方は
BigDecimal sample = BigDecimal.valueOf(0.008);
というように使います。
パターンその2:引数が1つでlong型
public static BigDecimal valueOf(long val)
long値をスケールが0のBigDecimalに変換します。この「staticファクトリ・メソッド」は、よく使われるBigDecimal値の再利用を可能にするため、(long)コンストラクタよりも優先して提供されます。
BigDecimal (Java Platform SE 8)から引用させて頂きました
使い方は
BigDecimal sample = BigDecimal.valueOf(4533333688588422888L);
というように使います。
パターンその3:引数が2つでlong型とint型
public static BigDecimal valueOf(long unscaledVal,int scale)
longのスケールなしの値とintのスケールをBigDecimalに変換します。この「staticファクトリ・メソッド」は、よく使われるBigDecimal値の再利用を可能にするため、(long, int)コンストラクタよりも優先して提供されます。
BigDecimal (Java Platform SE 8)から引用させて頂きました
使い方は
BigDecimal sample = BigDecimal.valueOf(4533333688588422888L, 1000);
というように使います。
BigDecimalの計算の仕方
BigDecimalではdouble型やint型のように「-」や「+」の演算子を使いません。
メソッドで計算します。
演算 | メソッド | 使用例 | 意味 |
---|---|---|---|
足し算 | add | a.add(b) | a + b |
引き算 | subtract | a.subtract(b) | a - b |
掛け算 | multiply | a.multiplyt(b) | a * b |
割り算 | divide | a.divide(b, 3, RoundingMode.HALF_UP) a.divide(b) |
a / b |
割り算だけ違いますね。
a.divide(b, 3, RoundingMode.HALF_UP)
引数が3つあるdivideメソッドは以下のような意味です
引数 | 意味 |
---|---|
1つ目の引数 | 割る数 |
2つ目の引数 | 小数点第何位までで丸めるのか |
3つ目の引数 | どのように丸めるのか 切り捨てなのか 四捨五入するのか |
を指定しています。
これで無限小数にならないようしています。
もちろん引数が1つのdivideメソッドでも計算することができますが、無限小数になった場合
Exception in thread "main" java.lang.ArithmeticException: Non-terminating decimal expansion; no exact representable decimal result.
at java.math.BigDecimal.divide(BigDecimal.java:1514)
at bigDecimalSample.BigDecimalSample.main(BigDecimalSample.java:30)>
というようにArithmeticException例外がスローされます。
無限小数になるときの丸め方はどのように設定するのか見ていきましょう。
BigDecimalの丸め方
丸め方を指定するRoundingModeはenumで定義されています。
丸め方を指定する場合
import java.math.RoundingMode;
をimportする必要があります。
RoundingModeは下記の種類があります。
丸めモード | 丸め方 |
---|---|
RoundingMode.CEILING | 切り上げ |
RoundingMode.DOWN | 0に近づくように丸める |
RoundingMode.FLOOR | 切り捨て |
RoundingMode.HALF_DOWN | 「もっとも近い数字」に丸める (両隣りの数字が等距離の場合は切り捨て) |
RoundingMode.HALF_EVEN | 「もっとも近い数字」に丸める (両隣りの数字が等距離の場合は偶数側に丸める) |
RoundingMode.HALF_UP | 四捨五入 |
RoundingMode.UNNECESSARY | 丸めが必要でないことを表す丸めモード |
RoundingMode.UP | 0から離れるように丸める |
計算と丸め方を解説しました。
次章で使い方を解説します。
スポンサーリンク
BigDecimalで色々な丸め方を使ってみる
どんな表示になるか実験してみます。
1÷0.7をして色んなRoundingModeで丸めてみます。
- RoundingMode.UNNECESSARYでエラーを起こさせる
- RoundingMode.UNNECESSARYを正常終了させる
の上記2パターンでやってみます
パターンその1:RoundingMode.UNNECESSARYでエラーを起こさせるJavaサンプルコード
package bigDecimalSample;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* RoundingModeを練習するクラス
* ※RoundingMode.UNNECESSARYでエラー
*
*/
public class RoundingModeSample {
public static void main(String[] args) {
BigDecimal cal1 = BigDecimal.ONE;
BigDecimal cal2 = BigDecimal.valueOf(0.7);
// 色んなRoundingModeを表示
System.out.println("計算結果 :1.428571428571429…");
System.out.println("RoundingMode.UP :"
+ cal1.divide(cal2, 5, RoundingMode.UP));
System.out.println("RoundingMode.DOWN :"
+ cal1.divide(cal2, 5, RoundingMode.DOWN));
System.out.println("RoundingMode.HALF_UP :"
+ cal1.divide(cal2, 5, RoundingMode.HALF_UP));
System.out.println("RoundingMode.HALF_DOWN :"
+ cal1.divide(cal2, 5, RoundingMode.HALF_DOWN));
System.out.println("RoundingMode.HALF_EVEN :"
+ cal1.divide(cal2, 5, RoundingMode.HALF_EVEN));
System.out.println("RoundingMode.CEILING :"
+ cal1.divide(cal2, 5, RoundingMode.CEILING));
System.out.println("RoundingMode.FLOOR :"
+ cal1.divide(cal2, 5, RoundingMode.FLOOR));
// 文法エラーは発生しないが、実行時にエラーが発生する
System.out.println("RoundingMode.UNNECESSARY:"
+ cal1.divide(cal2, 5, RoundingMode.UNNECESSARY));
}
}
実行結果
計算結果 :1.428571428571429…
Exception in thread "main" RoundingMode.UP :1.42858
RoundingMode.DOWN :1.42857
RoundingMode.HALF_UP :1.42857
RoundingMode.HALF_DOWN :1.42857
RoundingMode.HALF_EVEN :1.42857
RoundingMode.CEILING :1.42858
RoundingMode.FLOOR :1.42857
java.lang.ArithmeticException: Rounding necessary
at java.math.BigDecimal.commonNeedIncrement(BigDecimal.java:4148)
at java.math.BigDecimal.needIncrement(BigDecimal.java:4204)
at java.math.BigDecimal.divideAndRound(BigDecimal.java:4112)
at java.math.BigDecimal.divide(BigDecimal.java:5183)
at java.math.BigDecimal.divide(BigDecimal.java:1561)
at java.math.BigDecimal.divide(BigDecimal.java:1591)
at bigDecimalSample.RoundingModeSample.main(RoundingModeSample.java:34)
RoundingMode.UNNECESSARYは無限小数になった場合、 ArithmeticException例外 がスローされました。
丸めモードが必要ないって指定しているのに、答えが無限小数だからですね。
パターンその2:RoundingMode.UNNECESSARYを正常終了させるJavaサンプルコード
パターン2では、RoundingMode.UNNECESSARYは割り切れるようにして計算します。
package bigDecimalSample;
import java.math.BigDecimal;
import java.math.RoundingMode;
/**
* RoundingModeを練習するクラス
* ※RoundingMode.UNNECESSARYは正常終了
*
*/
public class RoundingModeSample {
public static void main(String[] args) {
BigDecimal cal1 = BigDecimal.ONE;
BigDecimal cal2 = BigDecimal.valueOf(0.7);
// 色んなRoundingModeを表示
System.out.println("計算結果 :1.428571428571429…");
System.out.println("RoundingMode.UP :"
+ cal1.divide(cal2, 5, RoundingMode.UP));
System.out.println("RoundingMode.DOWN :"
+ cal1.divide(cal2, 5, RoundingMode.DOWN));
System.out.println("RoundingMode.HALF_UP :"
+ cal1.divide(cal2, 5, RoundingMode.HALF_UP));
System.out.println("RoundingMode.HALF_DOWN :"
+ cal1.divide(cal2, 5, RoundingMode.HALF_DOWN));
System.out.println("RoundingMode.HALF_EVEN :"
+ cal1.divide(cal2, 5, RoundingMode.HALF_EVEN));
System.out.println("RoundingMode.CEILING :"
+ cal1.divide(cal2, 5, RoundingMode.CEILING));
System.out.println("RoundingMode.FLOOR :"
+ cal1.divide(cal2, 5, RoundingMode.FLOOR));
// RoundingMode.UNNECESSARYを正常終了するように計算する
System.out.println("RoundingMode.UNNECESSARY:"
+ cal1.divide(cal1, 5, RoundingMode.UNNECESSARY));
}
}
実行結果
計算結果 :1.428571428571429…
RoundingMode.UP :1.42858
RoundingMode.DOWN :1.42857
RoundingMode.HALF_UP :1.42857
RoundingMode.HALF_DOWN :1.42857
RoundingMode.HALF_EVEN :1.42857
RoundingMode.CEILING :1.42858
RoundingMode.FLOOR :1.42857
RoundingMode.UNNECESSARY:1.00000
無事計算結果が出力されました!
RoundingModeでは、
- RoundingMode.CEILING
- RoundingMode.DOWN
- RoundingMode.HALF_UP
を覚えておけば大抵の計算は賄えそうですかね。
スポンサーリンク
まとめ
以上がBigDecimalについての解説記事です。
この記事が皆さんのご参考になれば幸いです。
ではでは~(・ω・)ノシ
BigDecimal型とdouble型の比較記事も書いています。
こちらもご参考ください。
ほかにもJava解説記事を書いてます。
よければご参考ください。