概要
売上の前年比、KPI の達成率、原価率の算出など、割合計算は業務システムのあらゆる場面で登場します。double で計算すると丸め誤差が蓄積されるため、帳票や報告書の数値が微妙にずれるリスクがあります。とくに明細行ごとの割合を積み上げて合計を出す処理では、蓄積誤差が最終行で顕在化し、帳票の合計欄が手計算と一致しないという指摘につながることがあります。この記事では、BigDecimal を使った割合の算出、増減率の計算、百分率から実数への逆算を整理します。MathContext でスケールと丸めモードを管理する方法も紹介します。
使いどころ
月次レポートで売上の前月比・前年比を算出する
KPI ダッシュボードで達成率を小数第1位まで表示する
原価率から売価を逆算する
コード例
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
public class PercentageCalc {
private static final MathContext MC =
new MathContext(10, RoundingMode.HALF_UP);
public static BigDecimal percentage(
BigDecimal part, BigDecimal total) {
if (total.compareTo(BigDecimal.ZERO) == 0) {
throw new ArithmeticException("ゼロ除算");
}
return part.divide(total, MC)
.multiply(new BigDecimal("100"))
.setScale(1, RoundingMode.HALF_UP);
}
public static BigDecimal changeRate(
BigDecimal previous, BigDecimal current) {
return current.subtract(previous)
.divide(previous, MC)
.multiply(new BigDecimal("100"))
.setScale(1, RoundingMode.HALF_UP);
}
public static void main(String[] args) {
var total = new BigDecimal("2500");
var part = new BigDecimal("750");
System.out.println("割合: " +
percentage(part, total) + "%");
var prev = new BigDecimal("1000");
var curr = new BigDecimal("1250");
System.out.println("増減率: " +
changeRate(prev, curr) + "%");
}
}Version Coverage
var と record で計算結果を構造化できる。コードの意図が型で伝わりやすくなる。
// Java 17: var + record で計算結果を構造化
record CalcResult(BigDecimal value, String label) {}
var part = new BigDecimal("750");
var total = new BigDecimal("2500");
var result = new CalcResult(
percentage(part, total), "売上構成比");
System.out.println(result.label()
+ ": " + result.value() + "%");Library Comparison
注意点
割り算の結果が割り切れない場合は必ず RoundingMode を指定すること。
パーセント表示は「×100」するタイミングに注意。計算途中で百分率にしない。
ゼロ除算は事前チェックで防ぐ。BigDecimal.ZERO との比較には compareTo を使う。
FAQ
業務要件次第ですが、小数第1位か第2位が一般的です。setScale で統一します。
BigDecimal の符号がそのまま正負を表すため、表示時にマイナス記号を付けるだけです。
MathContext は有効桁数と丸めモードを管理し、setScale は小数点以下の桁数を指定します。用途に応じて使い分けます。