【解決Java】BigDecimalで四捨五入や切り捨ての丸め誤差を解決

こんにちは!フリーランスの長野です。

割り算を行う場合、計算結果の数値の小数点以下を四捨五入したり、切り上げ・切り捨てなどの端数処理をしたいことがありますよね。

そんな時にJavaではBigDecimalクラスを使用します。

この記事では、BigDecimalクラスについて

  • BigDecimalクラスとは
  • BigDecimalで小数点以下を誤差なく扱う方法
  • setScaleメソッドで丸め処理をする方法
  • divideメソッドで割り算の四捨五入をする方法
  • 小数点以下の桁数を指定する方法
  • マイナスの値の場合

などの基本的な内容から、具体的な使い方についても解説していきます。

今回はそんな端数の丸め処理について、さまざまな方法をわかりやすく解説します!

なお、Javaの記事については、こちらにまとめています。

目次

BigDecimalクラスとは

BigDecimalは小数点以下の値に誤差が出ないように正確に計算するために使います。

また、小数点以下を四捨五入したり、切り上げ・切り捨てなどの端数処理を行いたい場合に使用します。

それではBigDecimalを使って小数点以下を誤差なく扱う方法や、小数点以下の端数処理を行う方法について詳しくみていきましょう!

BigDecimalで小数点以下を誤差なく扱う方法

BigDecimalクラスを使用するには、以下のパッケージをインポートします。

import java.math.BigDecimal;

例えば、以下のようにインスタンスを作成して使用します。

String val = “123.456789”;
BigDecimal bd = new BigDecimal(val);

浮動小数点数ではなく文字列で指定

BigDecimalのコンストラクタの引数に浮動小数点数型と文字列型どちらも指定することができます。

しかし、引数に浮動小数点数型を指定した場合、誤差が発生するので注意が必要です。

正確な値を扱うためには、BigDecimalのコンストラクタの引数は文字列型で指定しましょう!

サンプルコードで確認していきましょう。

import java.math.BigDecimal;
 
public class Main {
 
    public static void main(String[] args) {
        BigDecimal bd1 = new BigDecimal(0.6); // 引数にdouble型で指定
        BigDecimal bd2 = new BigDecimal("0.6"); // 引数にString型で指定
        
        System.out.println(bd1);
        System.out.println(bd2);
    }
 
}

実行結果:

0.59999999999999997779553950749686919152736663818359375
0.6

このサンプルコードではBigDecimalのコンストラクタの引数をdouble型とString型で指定しています。

1つ目はdouble型で指定していますが、実行結果をみると誤差が発生しているのがわかります。

2つ目はString型で指定していますが、正確な値を表示できています。

四則演算用のメソッドを使った計算

BigDecimalクラスで使用する四則演算のメソッドは下記のとおりです。

メソッド説明
add()足し算
subtract()引き算
multiply()掛け算
divide()割り算

一般的な浮動小数点数型の四則演算の結果とBigDecimalクラスの四則演算用のメソッドを使った計算結果を比べてみましょう。

import java.math.BigDecimal;
 
public class Main {
    
    public static void main (String[] args) {
        // double型の四則演算
        System.out.println(2.0 - 6 * 0.3); 
        
        // BigDecimalクラスでの四則演算
        BigDecimal bd1 = new BigDecimal(2.0);
        BigDecimal bd2 = new BigDecimal(-6);
        BigDecimal bd3 = new BigDecimal("0.3");
        BigDecimal result = bd1.add(bd2.multiply(bd3));    
        System.out.println(result.toString());
    }
    
}

実行結果:

0.20000000000000018
0.2

このサンプルコードでは一般的なdouble型の四則演算とBigDecimalクラスを使った四則演算を行い、同じ式で同じ計算結果が得られるようにしています。

しかし、一般的なdouble型の四則演算の結果は0.2とは少し違って誤差が生じています。

これに対してBigDecimalクラスを使った四則演算の結果は意図通りの結果となっています。

setScaleメソッドで丸め処理をする方法

それでは、実際に端数の丸め処理をする方法を見ていきましょう。

BigDecimalクラスのsetScaleメソッドを使用します。

setScaleメソッドの引数で処理を行う桁数と丸め処理の方法の指定を行います。

メソッド第1引数:桁数を指定第2引数:丸目処理の方法を指定
説明説明
setScale0小数第1位BigDecimal.ROUND_HALF_UP四捨五入
1小数第2位BigDecimal.ROUND_DOWN切り捨て
2小数第3位BigDecimal.ROUND_UP切り上げ

桁数を指定して四捨五入をする方法

それでは四捨五入の処理をする場合の実際のコードとその処理結果をみていきましょう。

import java.math.BigDecimal;
 
public class Main {
 
    public static void main(String[] args) {
        //元データ
        String val = "123.456789";
        //インスタンスの作成
        BigDecimal bd = new BigDecimal(val);
        
        //小数第1位で四捨五入
        BigDecimal bd1 = bd.setScale(0, BigDecimal.ROUND_HALF_UP);
        //小数第2位で四捨五入
        BigDecimal bd2 = bd.setScale(1, BigDecimal.ROUND_HALF_UP);
        
        //実行結果
        System.out.println("小数第1位で四捨五入:" + bd1);
        System.out.println("小数第2位で四捨五入:" + bd2);
    }
 
}
小数第1位で四捨五入:123
小数第2位で四捨五入:123.5

マイナス値の四捨五入

マイナスの値を四捨五入したい場合もありますよね。結果は次のようになります。

import java.math.BigDecimal;
 
public class Main {
 
    public static void main(String[] args) {
        //元データ
        String val = "-123.456789";
        //インスタンスの作成
        BigDecimal bd = new BigDecimal(val);
        
        //小数第1位で四捨五入
        BigDecimal bd1 = bd.setScale(0, BigDecimal.ROUND_HALF_UP);
        //小数第2位で四捨五入
        BigDecimal bd2 = bd.setScale(1, BigDecimal.ROUND_HALF_UP);
        
        //実行結果
        System.out.println("小数第1位で四捨五入:" + bd1);
        System.out.println("小数第2位で四捨五入:" + bd2);
    }
 
}

実行結果:

小数第2位で四捨五入:-123
小数第2位で四捨五入:-123.5

切り捨て、切り上げをする方法

次に、切り捨て、切り上げの処理をする場合の実際のコードとその処理結果をみていきましょう。

import java.math.BigDecimal;
 
public class Main {
 
    public static void main(String[] args) {
        //元データ
        String val = "123.456789";
        //インスタンスの作成
        BigDecimal bd = new BigDecimal(val);
        
        //小数第1位で切り捨て
        BigDecimal bd1 = bd.setScale(0, BigDecimal.ROUND_DOWN);
        //小数第2位で切り捨て
        BigDecimal bd2 = bd.setScale(1, BigDecimal.ROUND_DOWN);
        
        //小数第1位で切り上げ
        BigDecimal bd3 = bd.setScale(0, BigDecimal.ROUND_UP);
        //小数第2位で切り上げ
        BigDecimal bd4 = bd.setScale(1, BigDecimal.ROUND_UP);
        
        //結果表示
        System.out.println("小数第1位で切捨て:" + bd1);
        System.out.println("小数第2位で切捨て:" + bd2);
        
        System.out.println("小数第1位で切上げ:" + bd3);
        System.out.println("小数第2位で切上げ:" + bd4);
    }
 
}

実行結果:

小数第1位で切捨て:123
小数第2位で切捨て:123.4
小数第1位で切上げ:124
小数第2位で切上げ:123.5

マイナス値の切り捨て、切り上げ

こちらもマイナスの値を処理したい場合もありますよね。結果は次のようになります。

import java.math.BigDecimal;
 
public class Main {
 
    public static void main(String[] args) {
        //元データ
        String val = "-123.456789";
        //インスタンスの作成
        BigDecimal bd = new BigDecimal(val);
        
        //小数第1位で切り捨て
        BigDecimal bd1 = bd.setScale(0, BigDecimal.ROUND_DOWN);
        //小数第2位で切り捨て
        BigDecimal bd2 = bd.setScale(1, BigDecimal.ROUND_DOWN);
    
        //小数第1位で切り上げ
        BigDecimal bd3 = bd.setScale(0, BigDecimal.ROUND_UP);
        //小数第2位で切り上げ
        BigDecimal bd4 = bd.setScale(1, BigDecimal.ROUND_UP);
     
        //結果表示
        System.out.println("小数第1位で切捨て:" + bd1);
        System.out.println("小数第2位で切捨て:" + bd2);
    
        System.out.println("小数第1位で切上げ:" + bd3);
        System.out.println("小数第2位で切上げ:" + bd4);
    }
 
}

実行結果:

小数第1位で切捨て:-123
小数第2位で切捨て:-123.4
小数第1位で切上げ:-124
小数第2位で切上げ:-123.5

divideメソッドで割り算の四捨五入をする方法

BigDecimalクラスには、四則演算用のメソッドが用意されていました。

メソッド説明
add()足し算
subtract()引き算
multiply()掛け算
divide()割り算

割り算で四捨五入をする場合は、2番目の引数で桁数の指定を、3番目の引数で丸め方法を指定します。

丸め方法はsetScaleメソッドと同じようになります。

それでは例をみてみましょう。

import java.math.BigDecimal;
 
public class Main {
 
    public static void main(String[] args) {
        // インスタンスの生成
        BigDecimal bd1 = new BigDecimal("5.0");
        BigDecimal bd2 = new BigDecimal("10.0");
        BigDecimal bd3 = new BigDecimal("3.0");
 
        // 足し算 ( 5.0 + 10.0 )
        BigDecimal add = bd1.add(bd2);
 
        // 引き算 ( 5.0 - 10.0)
        BigDecimal sub = bd1.subtract(bd2);
 
        // 掛け算 ( 5.0 * 3.0 )
        BigDecimal mul = bd1.multiply(bd3);
 
        // 割り算 ( 10.0 / 3.0 少数第3位で四捨五入)
        BigDecimal div = bd2.divide(bd3, 2, BigDecimal.ROUND_HALF_UP);
 
        System.out.println("足し算: " + add);
        System.out.println("引き算: " + sub);
        System.out.println("掛け算: " + mul);
        System.out.println("割り算: " + div);
    }
 
}

実行結果:

足し算: 15.0
引き算: -5.0
掛け算: 15.00
割り算: 3.33

ここで、注意があります。

割り算の場合、下記のように丸め処理を記述せずに割り切れない計算をすると無限小数となり、ArithmeticExceptionの例外が発生します。

BigDecimal div = bd2.divide(bd3);

compareToによるBigDecimal同士の比較

BigDecimalのオブジェクトを比較する場合は、compareToメソッドを使います。

compareToメソッドでBigDecimalのオブジェクトを比較する方法についてはこちらで詳しく解説していますので、参考にしてくださいね!

BigDecimalで正確に計算する方法総まとめ

BigDeciamlクラスを使って誤差なく正確に計算する方法については、次の記事にまとめているのでぜひ確認してみてくださいね!

まとめ

ここでは、端数の丸め処理について小数点の桁数の指定、丸め方法の指定、四則演算の方法について説明しました。

float型やdouble型では、演算処理の過程で誤差が積み重なり、正確な値が出力されない場合もあります。

厳密なお金の計算が必要な場合などはBigDecimalクラスを使って計算するようにしましょう。

普通の計算方法とは違うので慣れが必要かもしれませんが、そんな場合はこの記事を何度も参考にして下さいね!

この記事を書いた人

熊本在住のフリープログラマ兼ライターです。C/C++/C#、Java、Python、HTML/CSS、PHPを使ってプログラミングをしています。専門は画像処理で最近は機械学習、ディープラーニングにはまっています。幅広くやってきた経験を活かしてポイントをわかりやすくお伝えしようと思います。
お問合せはこちらでも受け付けています。
info@sss-lab.com

目次