Javaの四捨五入を完全解説|Math.round・BigDecimal・小数第n位の正しい方法

目次

1. Javaにおける「四捨五入」とは何か

Javaで「四捨五入」を行いたいと考えたとき、実は「これを使えば必ず四捨五入できる」という単一の方法は存在しません
理由は、Javaでは 扱う数値の型(int / double / BigDecimal など)や目的(計算用か表示用か)によって、適切な丸め方法が異なる ためです。

このセクションでは、まず前提となる考え方を整理し、なぜJavaの四捨五入が分かりにくいのかを明確にします。

1.1 四捨五入の基本ルール(5以上は切り上げ)

一般的な四捨五入のルールは次の通りです。

  • 対象の桁の 次の桁が5以上 → 切り上げ
  • 対象の桁の 次の桁が4以下 → 切り捨て

例(小数第1位で四捨五入)

  • 1.4 → 1
  • 1.5 → 2

このルール自体はJavaでも同じですが、問題は「どのメソッドがこのルールを適用するのか」「どの桁まで扱えるのか」 という点です。

Javaでは、四捨五入は以下のように目的別に分かれます

  • 単純な数値を丸めたい
  • 小数第n位で丸めたい
  • 金額計算など、誤差を絶対に出したくない

これらを同じ方法で処理しようとすると、意図しない結果になります。

1.2 Javaで四捨五入が分かりにくい理由

Javaの四捨五入が「難しい」「思った通りにならない」と言われる主な理由は、次の3点です。

理由1:浮動小数点数(double)の誤差

double2進数で小数を表現する型 です。
そのため、10進数ではキリが良い数でも、内部的には誤差を含むことがあります。

例:

double x = 0.1 + 0.2;
System.out.println(x); // 0.30000000000000004

この状態で四捨五入を行うと、人間の感覚と違う結果 になる場合があります。

理由2:「小数第n位で四捨五入」が直接できない

Javaには
「小数第2位で四捨五入する」
といった専用メソッドはありません。

そのため、多くの場合は次のような 計算式による調整 が必要になります。

  • 10倍・100倍する
  • 四捨五入する
  • 元のスケールに戻す

この手順を誤ると、結果がズレます。

理由3:メソッドごとに挙動と戻り値が違う

たとえば Math.round() は便利ですが、戻り値が整数型(int / long) になります。
「小数を残したまま丸めたい」という用途には、そのままでは使えません。

よくあるつまずきポイント・注意点

  • 「四捨五入=Math.round」と思い込む
    → 小数第2位以降や金額計算では不十分なケースが多い
  • doubleで金額計算をしてから丸める
    → 誤差が累積し、実務では危険
  • 表示用と計算用を同じ丸め処理にする
    → 内部計算まで丸めてしまい精度を失う

四捨五入は「結果を整える処理」であり、どの段階で・どの型に対して行うか が非常に重要です。

2. Math.round() を使った四捨五入(最も基本)

Math.round() は、Javaで最も基本的かつ手軽に四捨五入を行えるメソッドです。
初心者が最初に触れる方法として適していますが、使える範囲と制限を正しく理解していないと誤用しやすい点に注意が必要です。

このセクションでは、Math.round() の正しい使い方と、実務でつまずきやすいポイントを整理します。

2.1 Math.round() の基本的な使い方

Math.round() は、引数に指定した数値を 最も近い整数に四捨五入 します。

double a = 1.4;
double b = 1.5;

System.out.println(Math.round(a)); // 1
System.out.println(Math.round(b)); // 2

ポイントは以下の通りです。

  • 小数点以下 0.5以上で切り上げ
  • 0.5未満は切り捨て
  • 四捨五入のルールは一般的な定義どおり

一見すると直感的ですが、戻り値の型 が重要な注意点になります。

2.2 戻り値が int / long になる点に注意

Math.round() は、引数の型によって戻り値の型が変わります。

引数の型戻り値の型
floatint
doublelong

例:

double x = 3.7;
long result = Math.round(x);

ここで重要なのは、戻り値は必ず整数型になる という点です。

つまり、

  • 小数を含んだ結果を保持したい
  • 小数第1位や第2位まで残したい

といった用途では、そのままでは使えません。

よくある失敗例

double price = 12.34;
double rounded = Math.round(price); // 実際は long → double に代入

このコードはコンパイルエラーにはなりませんが、
小数部分は完全に失われ、12.0 になる ため注意が必要です。

2.3 小数第2位以降を四捨五入する方法(10倍・100倍テクニック)

Math.round() を使って 小数第n位で四捨五入 したい場合、
次のような手順を踏みます。

手順

  1. 対象の数値を 10ⁿ 倍する
  2. Math.round() で整数に丸める
  3. 再び 10ⁿ で割る

小数第2位で四捨五入する例

double value = 1.234;
double rounded = Math.round(value * 100) / 100.0;

System.out.println(rounded); // 1.23

小数第1位で四捨五入する例

double value = 1.25;
double rounded = Math.round(value * 10) / 10.0;

System.out.println(rounded); // 1.3

この方法は簡単ですが、double特有の誤差問題 を完全には回避できません。

つまずきポイント・注意点・よくある失敗

  • 割り算を整数で行ってしまうMath.round(value * 100) / 100; // 100 が int → 小数が消える → 必ず 100.0 のように double を使う
  • 金額計算にそのまま使う
    → 表示用なら可、計算用には不適切なケースが多い
  • 丸めるタイミングが早すぎる
    → 中間計算で丸めると、最終結果がズレやすい

Math.round() は「簡単に整数にしたい」「表示用に丸めたい」場面では便利ですが、
正確性が要求される処理には限界がある という点を必ず意識する必要があります。

3. 小数第n位で四捨五入する一般的な方法

「小数第2位で四捨五入したい」「小数第3位まで残したい」といった要望は非常に多く、
java 四捨五入 という検索キーワードの中心的な検索意図 でもあります。

このセクションでは、Math.round() を応用した 小数第n位指定の一般的な方法 と、
その方法が抱える限界を明確にします。

3.1 計算式の基本パターン

Javaでは、小数第n位で四捨五入する専用メソッドが存在しないため、
数値を一度スケール変換してから丸める という方法が広く使われます。

基本式

Math.round(値 × 10^n) ÷ 10^n

小数第2位で四捨五入する例

double value = 12.345;
double rounded = Math.round(value * 100) / 100.0;

System.out.println(rounded); // 12.35

小数第3位で四捨五入する例

double value = 12.34567;
double rounded = Math.round(value * 1000) / 1000.0;

System.out.println(rounded); // 12.346

この方法は理解しやすく、表示用の数値処理 では十分に実用的です。

3.2 うまくいかない例(0.1 + 0.2 問題)

しかし、この方法は double の誤差問題 を完全には回避できません。

代表的な例が次のケースです。

double value = 0.1 + 0.2;
double rounded = Math.round(value * 10) / 10.0;

System.out.println(value);   // 0.30000000000000004
System.out.println(rounded); // 0.3

一見問題なさそうに見えますが、計算内容や桁数によっては 意図しない丸め結果 が出る場合があります。

特に次のようなケースは危険です。

  • 金額計算
  • 税率・割合の累積計算
  • ループ内で何度も丸める処理

3.3 なぜ誤差が出るのか(超簡潔な補足)

double2進数で小数を表現する浮動小数点型 です。
そのため、10進数では正確な値でも、内部表現では誤差を含むことがあります。

これは Javaの仕様であり、バグではありません

よくある誤解

  • 「計算式が間違っている」 → ❌
  • 「Javaがおかしい」 → ❌
  • 「doubleの性質によるもの」 → ✅

つまずきポイント・注意点・よくある失敗

  • 10ⁿ倍・除算の順序を間違えるMath.round(value) * 100 / 100.0; // 意味がない
  • 除算で整数を使ってしまうMath.round(value * 100) / 100; // 小数が消える
  • 計算途中で何度も四捨五入する
    → 誤差が蓄積しやすい

この方法は「簡単・高速」ですが、正確さが求められる場面では不十分 であることを理解して使う必要があります。

4. BigDecimal を使った正確な四捨五入(推奨)

金額計算や税率計算など、誤差が許されない処理 ではdoubleMath.round() による四捨五入は適していません。

このようなケースで推奨されるのが BigDecimal を使った方法です。
BigDecimal10進数を正確に扱えるクラス であり、Javaにおける「正確な四捨五入」の標準的な解決策です。

4.1 BigDecimal を使うべきケース

次のような用途では、BigDecimal を使うべきです。

  • 金額(価格・請求額・残高)の計算
  • 税率・利率などの割合計算
  • 会計・金融・業務システム
  • 四捨五入結果の再現性が求められる処理

表示だけでなく計算結果そのものが重要な場合 は、double ではなく BigDecimal を選択するのが安全です

4.2 BigDecimal の正しい生成方法(new vs valueOf)

BigDecimal で最も多いつまずきポイントは、生成方法を間違えること です。

❌ 間違った例(非推奨)

BigDecimal bd = new BigDecimal(1.23);

この書き方は、double の誤差をそのまま引き継ぎます。

✅ 正しい例(推奨)

BigDecimal bd1 = new BigDecimal("1.23");
BigDecimal bd2 = BigDecimal.valueOf(1.23);
  • 文字列指定:最も安全
  • valueOf:内部で String に変換されるため安全

原則:new BigDecimal(double) は使わない と覚えておくと安心です。

4.3 setScale() と RoundingMode の使い方

BigDecimal で四捨五入を行うには、
setScale()RoundingMode を組み合わせます。

小数第2位で四捨五入する例

import java.math.BigDecimal;
import java.math.RoundingMode;

BigDecimal value = new BigDecimal("12.345");
BigDecimal rounded = value.setScale(2, RoundingMode.HALF_UP);

System.out.println(rounded); // 12.35
  • 第1引数:残したい小数桁数
  • 第2引数:丸めルール

RoundingMode.HALF_UP が、一般的な「四捨五入(5以上切り上げ)」に該当します。

つまずきポイント・注意点・よくある失敗

  • RoundingMode を指定しないvalue.setScale(2); // 例外が発生する場合あり
  • double → BigDecimal → 丸め の順が逆
    → 最初から BigDecimal で扱う
  • 表示用と計算用を混同
    → 計算用は BigDecimal、表示時のみフォーマット

BigDecimal はコード量が増えますが、正確さと安全性を最優先する場面では必須 です。

5. RoundingMode の種類と違い

BigDecimal で四捨五入を行う際、必ず理解しておくべきなのがRoundingMode(丸めモード) です。

RoundingMode は「どのルールで丸めるか」を明示的に指定する仕組みで、指定しない=処理内容が曖昧になる ため、実務では必須と考えてください。

5.1 HALF_UP(一般的な四捨五入)

RoundingMode.HALF_UP は、最も一般的な「四捨五入」 に該当します。

ルール

  • 次の桁が 5以上 → 切り上げ
  • 次の桁が 4以下 → 切り捨て

使用例

BigDecimal value = new BigDecimal("2.345");
BigDecimal rounded = value.setScale(2, RoundingMode.HALF_UP);

System.out.println(rounded); // 2.35

特別な理由がない限り、四捨五入は HALF_UP を選べば問題ありません。

5.2 HALF_DOWN / HALF_EVEN との違い

RoundingMode には、似た名前の丸め方が複数存在します。
ここで混乱する人が非常に多いため、違いを整理します。

HALF_DOWN

  • 5ちょうどの場合は 切り捨て
2.345 → 2.34

HALF_EVEN(銀行丸め)

  • 5ちょうどの場合、偶数になる方へ丸める
2.345 → 2.34
2.355 → 2.36

HALF_EVEN は誤差の偏りを抑える目的で使われ、金融・統計分野では指定されることがありますが、一般的な業務や初心者向け処理では不要 なケースがほとんどです。

5.3 どれを選べばいいかの判断基準

迷った場合の判断基準は明確です。

  • 一般的な四捨五入 → HALF_UP
  • 金融・規格指定あり → 仕様書に従う
  • 特別な理由がない → HALF_UP一択

よくある失敗

  • 「なんとなく HALF_EVEN を使う」
  • 「違いを知らずにコピペで指定する」

丸めモードは 仕様の一部 です。
明確な理由なく変更するべきではありません。

つまずきポイント・注意点・よくある失敗

  • RoundingMode を省略する
    → 実行時例外が発生することがある
  • 四捨五入=すべて HALF_UP だと思い込む
    → 業務仕様と食い違う可能性あり
  • チーム内で丸めルールが統一されていない
    → 計算結果の不一致につながる

6. よくあるつまずきポイント・注意点・失敗例

Javaの四捨五入は、文法やAPIを知っていても失敗しやすい分野 です。
このセクションでは、初心者〜中級者が実際によくやってしまう失敗を整理し、「なぜダメなのか」「どう回避すべきか」を明確にします。

6.1 doubleで金額計算している

最も多く、かつ危険な失敗がこれです。

double price = 1000.0;
double tax = price * 0.1;
double total = price + tax;

一見問題なさそうに見えますが、
double誤差を含む可能性がある型 のため、
金額計算では結果がズレるリスクがあります。

正しい考え方

  • 計算用:BigDecimal
  • 表示用:丸め・フォーマット
BigDecimal price = new BigDecimal("1000");
BigDecimal tax = price.multiply(new BigDecimal("0.1"));
BigDecimal total = price.add(tax);

6.2 四捨五入の順序が間違っている

四捨五入は、いつ行うか が重要です。

❌ 悪い例

double a = Math.round(x * 100) / 100.0;
double b = Math.round(a * y * 100) / 100.0;

途中計算で何度も丸めると、誤差が蓄積 します。

✅ 基本方針

  • 計算は最後まで行う
  • 四捨五入は 最終結果のみ

6.3 表示用と計算用を混同している

「画面に表示するための丸め」と「内部計算のための丸め」を混同すると、設計が破綻します。

よくある誤解

  • 表示で丸めた値を、そのまま次の計算に使う
  • UI仕様に合わせて計算ロジックを変更する

正しい分離

  • 内部計算:精度優先(BigDecimal)
  • 表示:フォーマット・丸め

6.4 RoundingMode を統一していない

コードの場所によって
HALF_UPHALF_DOWNHALF_EVEN が混在すると、
同じ計算でも結果が一致しない 事態が起きます。

対策

  • 丸めルールを定数として定義
  • チーム・プロジェクト単位で統一
static final RoundingMode ROUND_MODE = RoundingMode.HALF_UP;

つまずきポイント総まとめ

  • doubleは「計算できる」=「正確」ではない
  • 四捨五入は最後に一度だけ
  • 丸めルールは仕様として扱う
  • 表示と計算は分離する

これらを意識するだけで、四捨五入トラブルの大半は回避できます。

7. 実務での使い分け早見表(用途別)

ここまで解説してきた通り、Javaの四捨五入には複数の方法があり、
「どれが正解か」ではなく「用途ごとに正解が違う」 のが本質です。

このセクションでは、検索者が最短で判断できるよう、実務での使い分けを用途別に整理 します。

7.1 単純な数値を整数にしたい場合 → Math.round()

想定用途

  • 計算結果を整数で表示したい
  • 件数・人数・評価点など
  • 誤差が問題にならない処理

推奨方法

long result = Math.round(value);

注意点

  • 戻り値は int または long
  • 小数を保持したい場合には不向き

👉 「とりあえず整数にしたい」なら Math.round()

7.2 小数第n位まで表示したい場合 → Math.round() + スケール調整

想定用途

  • 画面表示用の数値
  • レポート・ログ出力
  • 厳密な計算精度が不要なケース

推奨方法(小数第2位)

double rounded = Math.round(value * 100) / 100.0;

注意点

  • double の誤差は残る
  • 計算用データには使わない

👉 表示専用であれば許容される方法

7.3 金額・税率・業務計算 → BigDecimal + HALF_UP

想定用途

  • 金額・請求・支払
  • 税率・割引率
  • 業務ロジック・永続化データ

推奨方法

BigDecimal rounded =
    value.setScale(2, RoundingMode.HALF_UP);

理由

  • 10進数を正確に扱える
  • 丸めルールを明示できる
  • 再現性が保証される

👉 実務ではこれが事実上の標準

7.4 判断に迷ったときの結論フロー

  • 「誤差が許されるか?」
    • YES → Math.round()
    • NO → BigDecimal
  • 「計算結果を保存・再利用するか?」
    • YES → BigDecimal
    • NO(表示のみ)→ Math.round()

よくある失敗(使い分け編)

  • 表示用コードをそのまま業務ロジックに流用
  • 金額なのに double を使い続ける
  • 「簡単だから」で Math.round() を多用

使い分けを一度整理しておくことで、後からの仕様変更やバグ修正コストを大幅に減らせます。

FAQ(よくある質問)

Q1. Javaで一番簡単に四捨五入する方法は何ですか?

A. 単純に整数へ丸めたい場合は Math.round() が最も簡単です。ただし戻り値は整数型になり、小数は保持できません。

Q2. 小数第2位(または第n位)で四捨五入するにはどうすればいいですか?

A. 表示用途であれば
Math.round(値 * 100) / 100.0
のようにスケール調整します。正確さが必要な場合は BigDecimal.setScale() を使います。

Q3. Math.round() を使っているのに結果がズレるのはなぜですか?

A. double の浮動小数点誤差が原因です。Javaの仕様であり、バグではありません。

Q4. 金額計算で Math.round() を使ってはいけませんか?

A. 推奨されません。金額・税計算では BigDecimal を使い、RoundingMode.HALF_UP で丸めるのが安全です。

Q5. BigDecimal を使っているのに誤差が出ることがあります

A. new BigDecimal(double) を使っている可能性があります。
new BigDecimal("1.23") または BigDecimal.valueOf(1.23) を使ってください。

Q6. RoundingMode はどれを選べばいいですか?

A. 一般的な四捨五入であれば RoundingMode.HALF_UP を選べば問題ありません。仕様指定がある場合はそれに従います。

Q7. 四捨五入は計算途中で行っても大丈夫ですか?

A. 推奨されません。途中で丸めると誤差が蓄積するため、最終結果のみ に適用するのが基本です。

Q8. 表示用と計算用で四捨五入方法を分けるべきですか?

A. はい。

  • 計算用:BigDecimal(精度優先)
  • 表示用:Math.round() やフォーマット
    と分離するのが正しい設計です。