Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Javaで想定しない小数点に悩まされるあなたへ

More than 1 year has passed since last update.

はじめに

こんばんは。またたびです。
前回の投稿から大幅に期間が空いてしまいました。。。

今回の記事ではJavaで小数点以下の計算も正確にしてくれるBigDecimalの使い方を記述していこうと思います。
なぜ小数点以下の計算を正確に行えるのかは今回触れませんので各自で調べていただければなと思います。
これから小数点以下の計算を正確に行いたい人の参考になれば幸いです。

BigDecimalを用いた四則演算(基礎)

それでは基本的なBigDecimalの記述方法について書いていきます。
BigDecimalを用いるには

.java
import java.math.BigDecimal;

をインポートする必要があります。
標準ライブラリですので特に外部から持ってくる必要はなく、すぐに使用が可能です。
以下に記述方法と使用例を示していきます。

四則演算 記述方法
加算 add
減算 subtract
乗算 multiply
除算 divide
Main.java
import java.math.BigDecimal;
public class Main {
    public static void main(String[] args) {
        //値の定義
        int one = 1;
        int two = 2;
        BigDecimal three = BigDecimal.valueOf(3);
        BigDecimal five = BigDecimal.valueOf(5);

        //基本
        System.out.println(three.add(five));//8
        System.out.println(three.subtract(five));//-2
        System.out.println(three.multiply(five));//15
        System.out.println(three.divide(five));//0.6

        //少し応用
        System.out.println(BigDecimal.valueOf(two).add(BigDecimal.valueOf(one)).multiply(three));//9
    }
}

このような記述が可能になります。
またコメント部分の少し応用に示している通り、いくつも続けて記述が可能になっています。(これを知らずに半年BigDecimalを使っていました…)

BigDecimalを用いた小数点計算

ここから小数点を扱う計算になります。
Java9以降ではROUND_UP等の記述は非推奨ですので、本記事で用いているUP等の記述を用いていただければと思います。
BogDecimalでは小数点以下の値を切り捨てや四捨五入が可能になります。
この処理を行うにはsetScaleメソッドを使用します。
第一引数には小数点第何位に制御を行うかを記述します。
例えば、setscaleの第一引数が0であった場合は小数点第一位に制御を行います。
以下に記述方法と使用例を記述していきます。

丸め込みの方法 記述方法
四捨五入 HALF_UP 
切り上げ UP
切り捨て DOWN
Main.java
import java.math.BigDecimal;
import java.math.RoundingMode;
public class Main {
    public static void main(String[] args) {
        //値の定義
        BigDecimal one = BigDecimal.valueOf(1);
        BigDecimal three = BigDecimal.valueOf(3);
        BigDecimal num = new BigDecimal("1.567");

        //基本
        System.out.println(num.setScale(0,RoundingMode.HALF_UP));//2
        System.out.println(num.setScale(1,RoundingMode.DOWN));//1.5
        System.out.println(num.setScale(2,RoundingMode.UP));//1.57

        //少し応用
        System.out.println(one.divide(three).setScale(2,RoundingMode.DOWN));//error
        System.out.println(one.divide(three,2,RoundingMode.DOWN));//0.3
    }
}

値の定義の3行目にて変数宣言と代入が1、2行目と異なっています。
これについてですが、BigDecimalを用いたとしても小数点を完璧に扱えない場合があります。
これの対策として、BigDecimalで小数点を用いる際にはStringで扱ったほうがいいです。
String型ですがこのまま計算してくれます。

少し応用の2行目で特殊な記述をしました。
そこについて説明させていただきます。
BigDecimal型の除算では循環小数が発生する場合(今回の場合は0.3333......)
java.lang.ArithmeticExceptionの例外が発生します。
その対策方法としてBigDecimalでは少し応用の2行目のような記述が可能です。
この記述であれば例外を発生させることなくプログラムの記述が可能になります。

BigDecimalの型変換

BigDecimalで小数点の計算を終えた後、その値をプリミティブ型で使用したいということがあると思います。
そのため最後にBigDecimal型からint型やdouble型に変換する方法を記述していきます。
例としてint型とdouble型を示します。

変換したい型 記述方法
int intValue()
double doubleValue()
Main.java
import java.math.BigDecimal;
public class Main {
    public static void main(String[] args) {
        //値の定義
        BigDecimal one = BigDecimal.valueOf(1);
        BigDecimal num = new BigDecimal("1.567");
        int a;
        double b;

        //型変換
        a = one.intValue();
        b = num.doubleValue();
    }
}

このように記述することで、BigDecimalで計算した値をプリミティブ型に変換することが可能になります。

おわりに

今回はJavaにて小数点以下の計算を正確に行う際に用いられることの多い、BigDecimalの基礎的な記述部分について書きました。
他にもBigDecimalの大小比較や、べき乗など便利なメソッドが多くありますので調べてみてください。
もう少し詳しく知りたいというご意見があれば記事を追記するかもしれません。(書きたい気持ちはありますが忙しさ次第…)
間違えている部分や表現がおかしい部分、こうしたほうがもっと綺麗に記述可能である部分等ありましたら、私の勉強になりますので是非コメントください。
ここまで読んでいただきありがとうございました。

matatabi_data
しがない大学院生をやっております。 Twitterをやっておりますのでフォローお待ちしております。頻度は() @matatabi_data
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away