読み込み中...

Javaでの切り捨ての10選手法

Java言語のロゴと、横に「Javaでの切り捨ての10選手法」というテキスト Java
この記事は約29分で読めます。

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

本記事のサンプルコードを活用して機能追加、目的を達成できるように作ってありますので、是非ご活用ください。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を満たす現役のプログラマチームによって監修されています。

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Javaで小数を扱うとき、表示用に桁をそろえる処理と、計算用に値そのものを丸める処理は分けて考える必要があります。そのため、切り捨てを行う場面ではMath.floorBigDecimalRoundingMode.DOWN、型変換、Streamなどの違いを押さえると、初心者でも処理の意図を読み取りやすくなります。

このJavaプログラミング記事では、元記事の構成を保ちながら、切り捨ての考え方、サンプルコード、注意点、カスタマイズの方法を整理するのが基本です。一方で、動作未確認の断定を避けるため、コード直後の出力は「期待される出力」として示します。

公式ドキュメントを確認しながら学ぶ場合は、Java標準APIのMathクラスBigDecimalクラスが一次情報になります。関連する基礎として、Java List型完全ガイドJavaエスケープ処理の解説も併せて読むと理解しやすくなるのが目安です。

動作確認環境
  • Java SE 21
  • Apache Maven 3.9系を想定
  • Apache Commons Math 3.6.1を外部ライブラリ例で使用
📖 この記事で学べること
  • Javaで小数を切り捨てる代表的な方法
  • Math.floorと型変換の違い
  • BigDecimalで桁数を制御する考え方
  • 配列、ListStreamに対する一括処理
  • 丸め誤差や負の数を扱うときの注意点

Javaとは

Javaは、クラスを中心にコードを組み立てるオブジェクト指向のプログラミング言語です。そのコードはjavac.classへコンパイルされ、JVM上で動くため、OS差を吸収しやすい設計になっています。

一般に、Javaは業務システム、Webアプリケーション、Android関連の開発、バッチ処理などで利用されます。一方で、数値処理ではdoublefloatの特性を理解しないと、表示値と内部値の差に戸惑うことがあるのがポイントです。

そのため、Javaで切り捨てを扱うときは、単に小数点以下を消すだけでなく、どの型に変換するのか、負の値をどう扱うのか、金額計算に使ってよいのかを確認します。初心者はMath.floorから入り、上級者はBigDecimalRoundingModeの選択まで含めて設計すると整理できます。

Javaの基本的な特性

これらの特性の中で、切り捨てに関係するのは静的型付けと標準ライブラリの範囲です。intlongdoubleBigDecimalは性質が異なるため、同じ値を扱っていても結果の型や精度が変わりますし、ここがポイントです。

たとえば、(int) 5.9は小数部を落として5になりますが、Math.floor(5.9)double5.0を返します。一方、BigDecimalは小数の桁数と丸め方を明示できるため、金額や税率のような値を扱うサンプルコードで採用されやすい方法です。

ちなみに、公式ドキュメントによればMath.floorは引数以下の最大の数学的整数に等しいdoubleを返します。この仕様により、正の値では小数部を削る感覚に近くなりますが、負の値では-5.2-6.0になる点に注意が必要です。

切り捨てとは

切り捨てとは、指定した桁より下の値を落とす数値処理です。その対象は整数化だけではなく、小数点第2位まで残す、10円未満を落とす、基準値を超えた値だけ処理する、といったプログラミング上の要求にも広がりますが、これは押さえたい点です。

一方で、四捨五入、切り上げ、切り捨ては別の操作です。JavaではMath.roundが四捨五入寄り、Math.ceilが切り上げ、Math.floorが下方向への丸めを表すため、名前だけで選ばず仕様を確認する必要があります。

具体的には、表示だけを整えたいときはDecimalFormatString.formatが候補になります。ただし、計算に使う値そのものを変えるなら、BigDecimal#setScaleや算術式による方法のほうが目的に合いるのが一般的です。

分類主なAPI向く場面戻り値の傾向注意点
整数方向Math.floor正の小数を下方向へ丸めるdouble負の数は小さい方向へ進む
型変換(int)小数部だけ落とすint範囲外や負数に注意
長整数(long)大きめの整数化long小数部は0方向に落ちる
金額計算BigDecimal桁数と丸め方を明示BigDecimal文字列から生成する
丸めモードRoundingMode.DOWN0方向への切り捨て指定API次第FLOORとの違いを見る
下方向RoundingMode.FLOOR数学的な床関数指定API次第負数で差が出る
表示整形DecimalFormat画面表示をそろえるString計算値ではない
四捨五入Math.round近い整数へ丸めるlong切り捨てではない
切り上げMath.ceil上方向へ丸めるdouble目的を混同しない
配列処理for全要素を更新配列元配列を書き換える
拡張forfor-each読み取り中心要素代入更新には不向き
リスト処理Listコレクション管理List可変性を確認する
ストリームstream変換処理の連鎖Stream終端操作が必要
変換map各要素を変換Stream型変換を明示する
収集collect結果をリスト化ListJavaバージョンで書き方が変わる
出力System.out.println学習用の確認標準出力本番ログとは分ける
乱数Math.random簡易的な乱数double再現性は低い
基準値if条件付き処理分岐境界値を決める
小数桁setScale桁数指定BigDecimal丸めモード必須の場面がある
加算add精度を保つ計算BigDecimal+ではない
文字列化toPlainString指数表記を避けるString表示用途に向く
依存関係pom.xmlMaven管理設定バージョン固定が必要
外部APIPrecision.roundライブラリ例double標準APIで足りる場合もある
負数処理RoundingMode.DOWN0方向に落とす指定API次第floorと異なる
境界値threshold条件判定boolean等号の扱いを見る
平均sum集計処理double丸める位置を決める
桁倍率100.0小数第2位まで残すdouble誤差を含むことがある
クラスpublic class実行単位型定義ファイル名と合わせる
入口main学習用コードの開始点void引数配列を持つ
例外ArithmeticException丸め指定不足の理解例外必要に応じて対処する

Javaでの切り捨ての10の方法

Javaで切り捨てを行う方法は、標準APIだけでも複数あります。特に押さえたいのは、値を下方向へ丸めるMath.floor、小数部を0方向へ落とす型変換、桁数を明示できるBigDecimalです。

その違いを理解しておくと、サンプルコードを写すだけでなく、プログラミング上の要件に合わせて選べます。初心者は出力の型と負数の扱い、上級者は精度とメンテナンス性を判断材料にするとよいでしょう。

切り捨ての基本

基本的に、整数にするだけならMath.floorまたは型変換で足りますし、これが一つの目安です。ただし、Math.floorは下方向へ丸め、(int)は0方向へ小数部を落とすため、負の数を扱うと結果が一致しない場合があります。

具体的には、5.7ならどちらも見た目は5に近い値になります。一方、-5.7ではMath.floor-6.0(int)-5となるため、切り捨てという言葉だけでは設計判断が足りません。

サンプルコード1:Mathクラスを利用した切り捨て

JavaのMath.floorは、引数以下の最大の整数値をdoubleとして返するのが現実的です。そのため、正の小数を整数方向へ落とす用途では読みやすい方法になります。

public class Main {
    public static void main(String[] args) {
        double num = 5.7;
        double result = Math.floor(num);
        System.out.println("切り捨て後の数値は: " + result);
    }
}

結果: 期待される出力は「切り捨て後の数値は: 5.0」です。

このとき、戻り値はintではなくdoubleです。そのため、整数型として使うなら(int)(long)への変換を別途検討します。

一方、Math.rintは切り捨てではなく、最も近い整数へ丸めるAPIです。.5付近では偶数方向の丸めが関係するため、サンプルコード上でも目的を分けて読んでください。

public class Main {
    public static void main(String[] args) {
        double num = 5.5;
        double result = Math.rint(num);
        System.out.println("丸め後の数値は: " + result);
    }
}

結果: 期待される出力は「丸め後の数値は: 6.0」です。

サンプルコード2:BigDecimalクラスを利用した切り捨て

金額や小数桁を厳密に扱うJavaプログラミングでは、BigDecimalを使う方法がよく選ばれます。ただし、new BigDecimal(0.1)のようにdoubleから直接作ると誤差を含むため、文字列から生成するのが一般的です。

import java.math.BigDecimal;

結果: この行だけでは画面表示はありませんが、BigDecimalをクラス内で参照できるようになります。

これを使って小数点以下の桁数を制御するには、setScaleに桁数とRoundingModeを渡すると整理できます。古い定数であるBigDecimal.ROUND_DOWNは避け、現在のコードではRoundingMode.DOWNを使う書き方が読みやすくなります。

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

public class BigDecimalExample {
    public static void main(String[] args) {
        BigDecimal bd = new BigDecimal("3.14159");
        bd = bd.setScale(2, RoundingMode.DOWN);
        System.out.println("切り捨て後の値: " + bd.toPlainString());
    }
}

結果: 期待される出力は「切り捨て後の値: 3.14」です。

その結果、3.14159は小数点以下2桁まで残り、それより下の桁が落ちます。toPlainStringを使うと指数表記を避けやすいため、表示用のサンプルコードとしても読みやすくなります。

サンプルコード3:小数点以下の桁数指定による切り捨て

小数点以下の桁数をそろえる処理では、値そのものを変える方法と文字列として整形する方法があると理解できます。DecimalFormatは表示整形に向く一方、計算用の値として保持するならBigDecimalのほうが意図を表しやすいです。

import java.math.RoundingMode;
import java.text.DecimalFormat;

public class DecimalTruncate {
    public static void main(String[] args) {
        double number = 123.456;
        DecimalFormat df = new DecimalFormat("0.00");
        df.setRoundingMode(RoundingMode.DOWN);
        String result = df.format(number);
        System.out.println("切り捨て後の値: " + result);
    }
}

結果: 期待される出力は「切り捨て後の値: 123.45」です。

このサンプルコードでは、DecimalFormatRoundingMode.DOWNを設定しています。初期設定のままでは丸め方が要件とずれる場合があるため、切り捨て目的なら丸めモードを明示するのが現実的です。

ただし、得られるresultStringです。そのため、後続の計算で使う値ではなく、画面や帳票に表示する値として扱うと整理できます。

切り捨ての応用

応用では、切り捨てだけでなく、比較対象として四捨五入や切り上げも確認すると覚えるとよいでしょう。その違いを知ると、同じ数値を扱うJavaのサンプルコードでも、なぜ結果が変わるのかを説明しやすくなります。

一方、業務ロジックでは「小数を落とす」よりも、「基準値を超えた場合だけ落とす」「配列全体を変換する」「乱数を整数化する」といった条件付きの方法が必要になることがあります。こうした処理は、制御構文やコレクション操作と組み合わせると自然に書けると考えられます。

サンプルコード4:四捨五入による丸め

Math.roundは切り捨てではなく、近い整数へ丸めるAPIです。ただし、切り捨てとの差を説明するうえで比較対象になるため、初心者が混同しやすい処理として確認しておく価値があります。

public class Main {
    public static void main(String[] args) {
        double val = 3.14159;
        long roundedVal = Math.round(val);
        System.out.println("四捨五入後の値は:" + roundedVal + " です");
    }
}

結果: 期待される出力は「四捨五入後の値は:3 です」です。

この例では3.141593に近いため、見た目だけでは切り捨てと同じ結果になります。逆に3.6を渡すと4になるため、切り捨ての代替として使う方法ではありません。

サンプルコード5:切り上げ

切り上げは、切り捨てとは反対方向の丸めです。JavaのMath.ceilは引数以上の最小の整数値に等しいdoubleを返すため、端数が少しでもあれば上方向へ進みます。

public class CeilExample {
    public static void main(String[] args) {
        double number = 5.3;
        double result = Math.ceil(number);
        System.out.println("切り上げ結果:" + result);
    }
}

結果: 期待される出力は「切り上げ結果:6.0」です。

この処理は、在庫数、人数、ページ数のように不足を避けたい計算で候補になると言えるでしょう。一方、端数を落とすプログラミング要件ではMath.floorRoundingMode.DOWNと使い分けます。

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

public class BigDecimalCeilExample {
    public static void main(String[] args) {
        BigDecimal number = new BigDecimal("5.3");
        BigDecimal result = number.setScale(0, RoundingMode.UP);
        System.out.println("切り上げ結果:" + result.toPlainString());
    }
}

結果: 期待される出力は「切り上げ結果:6」です。

このRoundingMode.UPは0から離れる方向への丸めです。そのため、負の値を含む場合はCEILINGFLOORとの違いを確認してから選ぶ必要があります。

サンプルコード6:特定の基準値をもとにした切り捨て

条件付きで切り捨てる方法は、しきい値を超えた場合だけ丸めたい場面に向きます。たとえば、入力値が一定以上なら整数化し、それ以下なら元の値を残すという仕様はifで表現できるのが基本です。

public class Main {
    public static void main(String[] args) {
        double originalValue = 5.7;
        double threshold = 5.5;

        if (originalValue > threshold) {
            originalValue = Math.floor(originalValue);
        }

        System.out.println("切り捨て後の数値: " + originalValue);
    }
}

結果: 期待される出力は「切り捨て後の数値: 5.0」です。

このとき、originalValuethresholdより大きい場合だけMath.floorが呼ばれます。一方、同じ値を基準に含めたいなら>=を使うなど、境界値の仕様を先に決めるのが基本になります。

サンプルコード7:配列内の値を一括で切り捨て

配列内の値をまとめて切り捨てる場合、インデックス付きのfor文が扱いやすいです。要素を書き換えるため、numbers[i]へ代入できる形で走査するのが目安です。

public class ArrayTruncate {
    public static void main(String[] args) {
        double[] numbers = {1.7, 2.8, 3.5, 4.9, 5.6};

        for (int i = 0; i < numbers.length; i++) {
            numbers[i] = Math.floor(numbers[i]);
        }

        for (double number : numbers) {
            System.out.println(number);
        }
    }
}

結果: 期待される出力は、各行に「1.0」「2.0」「3.0」「4.0」「5.0」が並ぶ形です。

その後の表示では、拡張for文を使って各要素を読み取っています。読み取りと更新でループの役割を分けると、初心者でもコードの流れを追いやすくなります。

1.0
2.0
3.0
4.0
5.0

結果: これは上の配列処理で期待される出力例です。

同様に、切り捨てた値を集計に回す方法もあるのがポイントです。集計前に丸めるのか、集計後に丸めるのかで平均値が変わる場合があるため、プログラミング上の仕様として順序を明確にします。

public class AdvancedArrayTruncate {
    public static void main(String[] args) {
        double[] numbers = {1.7, 2.8, 3.5, 4.9, 5.6};
        double sum = 0;

        for (int i = 0; i < numbers.length; i++) {
            numbers[i] = Math.floor(numbers[i]);
            sum += numbers[i];
        }

        double average = sum / numbers.length;
        System.out.println("The average of the truncated values is: " + average);
    }
}

結果: 期待される出力は「The average of the truncated values is: 3.0」です。

サンプルコード8:ストリームを使用した切り捨て処理

Streamを使うと、リスト内の値を変換して別のリストに集める流れを短く書けます。元のList<Double>を残しつつ、整数化したList<Integer>を作る方法として読みやすいです。

import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

public class TruncateUsingStreams {
    public static void main(String[] args) {
        List<Double> numbers = Arrays.asList(1.1, 2.2, 3.3, 4.4, 5.5);
        List<Integer> truncatedNumbers = numbers.stream()
                .map(Double::intValue)
                .collect(Collectors.toList());

        truncatedNumbers.forEach(System.out::println);
    }
}

結果: 期待される出力は、各行に「1」「2」「3」「4」「5」が並ぶ形です。

この例のDouble::intValueは0方向に小数部を落とします。そのため、負の数を下方向に丸めたい場合はd -> (int) Math.floor(d)のように目的を明示すると誤読を減らせます。

1
2
3
4
5

結果: これはストリーム処理で期待される出力例です。

この書き方は、変換、抽出、集計を連鎖させる処理に向きますが、覚えておくと役立つでしょう。一方で、単純な配列更新なら通常のfor文のほうが読みやすい場合もあるため、上級者ほど処理の複雑さに合わせて選択します。

サンプルコード9:ランダムな数値の切り捨て

乱数を整数化する処理では、Math.randomで得たdoubleを倍率で広げてからMath.floorに渡します。簡易的なサンプルコードとしては読みやすいものの、再現性が必要なテストではRandomSplittableRandomも候補になるのが一般的です。

public class RandomNumberTruncation {
    public static void main(String[] args) {
        double randomNumber = Math.random() * 100;
        System.out.println("生成されたランダムな数値: " + randomNumber);

        double truncatedNumber = Math.floor(randomNumber);
        System.out.println("切り捨て後の数値: " + truncatedNumber);
    }
}

結果: 期待される出力は実行ごとに変わりますが、「生成されたランダムな数値: 59.3748」のような値に続き、「切り捨て後の数値: 59.0」のような値が表示されます。

この方法では、Math.random()0.0以上1.0未満の値を返します。その値に100を掛けるため、切り捨て後は0.0から99.0までの範囲になるのが現実的です。

サンプルコード10:外部ライブラリを利用した切り捨て

外部ライブラリを使う方法は、既存プロジェクトでApache Commons Mathを利用している場合に候補になります。ただし、単純な切り捨てだけならJava標準APIで足りることも多いため、依存関係を増やす理由を明確にします。

Apache Commons Mathの情報はApache Commons Math公式サイトで確認できると整理できます。Mavenプロジェクトでは、pom.xmlに依存関係を追加してから利用します。

<dependency>
    <groupId>org.apache.commons</groupId>
    <artifactId>commons-math3</artifactId>
    <version>3.6.1</version>
</dependency>

結果: この設定はMavenの依存関係を追加するもので、単体では画面表示はありません。

外部ライブラリ例では、Precision.roundに丸め方を渡して小数桁を制御できます。ただし、Commons Math 3系の丸め指定は古いBigDecimal定数を受け取る形のAPIが残るため、新規コードでは標準のBigDecimalを優先する判断も自然です。

import java.math.BigDecimal;
import org.apache.commons.math3.util.Precision;

public class TruncateExample {
    public static void main(String[] args) {
        double number = 123.456789;
        double truncatedNumber = Precision.round(number, 2, BigDecimal.ROUND_DOWN);
        System.out.println("元の数値: " + number);
        System.out.println("切り捨て後の数値: " + truncatedNumber);
    }
}

結果: 期待される出力は「元の数値: 123.456789」と「切り捨て後の数値: 123.45」です。

このコードは既存APIの説明を目的にした例です。新しいJavaコードで丸め方を明示するなら、RoundingMode.DOWNを使ったBigDecimal#setScaleのほうが読み手に意図が伝わりやすくなります。

元の数値: 123.456789
切り捨て後の数値: 123.45

結果: これは外部ライブラリ例で期待される出力例です。

切り捨て時の注意点と対処法

Javaで切り捨てを扱うときに初心者がつまずきやすいのは、丸め誤差、負の数、パフォーマンス、表示と計算の混同です。そのため、単に出力が期待に近いかを見るだけでなく、値の型と処理タイミングを確認します。

一方で、上級者向けの設計では、精度が必要な箇所だけBigDecimalを使い、単純な表示や一時的な整数化では軽い方法を選ぶ判断が求められますし、ここを基本と考えるとよいでしょう。Javaアノテーションの解説Javaオーバーライドの解説のように、言語仕様を分けて学ぶとコードレビューでも説明しやすくなります。

丸め誤差の問題

浮動小数点数のdoubleは、多くの小数を2進数で近似して保持します。そのため、0.1を足し合わせるような処理では、期待する10進表現と内部値に差が出ることがあると理解できます。

public class RoundingErrorExample {
    public static void main(String[] args) {
        double number = 0.1;
        double sum = number + number + number;

        System.out.println("期待される結果: 0.3");
        System.out.println("実際の結果: " + sum);
    }
}

結果: 期待される出力は「期待される結果: 0.3」に続き、環境により「実際の結果: 0.30000000000000004」のような近似値が表示される形です。

この問題はJava固有というより、2進浮動小数点数の一般的な性質です。そのため、金額や厳密な小数計算ではBigDecimalを文字列から生成し、addなどのメソッドで計算します。

import java.math.BigDecimal;

public class BigDecimalExample {
    public static void main(String[] args) {
        BigDecimal number = new BigDecimal("0.1");
        BigDecimal sum = number.add(number).add(number);

        System.out.println("期待される結果: 0.3");
        System.out.println("実際の結果: " + sum.toPlainString());
    }
}

結果: 期待される出力は「期待される結果: 0.3」と「実際の結果: 0.3」です。

このように、切り捨て前の値がすでに誤差を含んでいると、丸めた後の値にも影響する場合があります。プログラミングでは、切り捨て処理だけでなく、値を生成する段階から精度を考える必要があります。

⚠️ 注意: new BigDecimal(0.1)doubleの近似値を受け取るため、厳密な10進小数として扱いたい場合はnew BigDecimal("0.1")を使いると覚えるとよいでしょう。

パフォーマンスへの影響

大量データに対する切り捨てでは、処理回数が増えるほど計算コストが見えやすくなります。ただし、簡易的な時間計測だけで結論を出すと誤解につながるため、学習用コードと性能評価は分けて扱うのが現実的です。

public class PerformanceOptimizationExample {
    public static void main(String[] args) {
        long startTime = System.nanoTime();

        double number = 12345.6789;
        double result = 0;
        for (int i = 0; i < 1_000_000; i++) {
            result = Math.floor(number);
        }

        long endTime = System.nanoTime();

        System.out.println("最後の計算結果: " + result);
        System.out.println("処理時間: " + (endTime - startTime) + " ナノ秒");
    }
}

結果: 期待される出力は「最後の計算結果: 12345.0」と、環境により変動する処理時間です。

このサンプルコードは学習用の目安であり、厳密な性能評価ではありません。一般的に、JITコンパイル、ウォームアップ、CPU状態、GCの影響を受けるため、本格的な計測ではJMHのような専用ツールが使われます。

そのため、速度が気になる場合でも、先に不要な切り捨てを減らす、ループ外へ移せる処理を移す、表示直前だけ整形する、といった設計上の方法を検討します。Javaのうるう年判定のような条件分岐記事も、境界値の考え方を学ぶ補助になると考えられます。

💡 Tips: 表示のためだけに桁をそろえるなら、計算の途中で何度も切り捨てず、出力直前に整形する方法を検討します。

切り捨てのカスタマイズ方法

切り捨てのカスタマイズでは、桁数、丸め方向、条件、対象データを分けて考えます。その設計が曖昧なままだと、正の値では正しく見えても、負の値や境界値で仕様と異なる結果になるかもしれません。

具体的には、単価計算なら小数点以下の扱い、在庫や人数なら整数化の方向、集計なら丸める順序が論点になると言えるでしょう。Javaの方法を選ぶ前に、どの値を、どの桁で、どのタイミングで処理するかを決めると実装が安定します。

カスタム切り捨てロジックの作成

独自ロジックでは、倍率を掛けて整数化し、元の桁へ戻す方法がよく使われます。ただし、doubleのまま計算するため、金額のように厳密性が必要な場面ではBigDecimal版を選びますし、ここがポイントです。

public class CustomTruncate {
    public static void main(String[] args) {
        double originalValue = 123.456;
        double truncatedValue = (double) ((int) (originalValue * 100)) / 100;
        System.out.println("元の値: " + originalValue);
        System.out.println("切り捨て後の値: " + truncatedValue);
    }
}

結果: 期待される出力は「元の値: 123.456」と「切り捨て後の値: 123.45」です。

この式では、originalValue * 100で小数第2位までを整数部へ移動し、(int)で小数部を落としてから100で戻しています。一方、負の値では0方向への丸めになるため、数学的な床関数とは違う結果になります。

同様の処理を再利用したい場合は、独自メソッドに切り出す方法が扱いやすいです。桁数を引数にすれば、サンプルコードを固定値から実用寄りの形へ変えられますが、これは押さえたい点です。

public class CustomTruncateMethod {
    public static void main(String[] args) {
        double value = 987.6543;
        System.out.println(truncate(value, 2));
    }

    static double truncate(double value, int scale) {
        double factor = Math.pow(10, scale);
        return ((long) (value * factor)) / factor;
    }
}

結果: 期待される出力は「987.65」です。

ただし、この方法は桁数が大きい場合や値が大きい場合に限界があります。そのため、上級者向けの実装では、要件に応じてBigDecimal版のメソッドを用意するほうが保守しやすくなります。

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

public class BigDecimalTruncateMethod {
    public static void main(String[] args) {
        BigDecimal value = new BigDecimal("987.6543");
        System.out.println(truncate(value, 2));
    }

    static BigDecimal truncate(BigDecimal value, int scale) {
        return value.setScale(scale, RoundingMode.DOWN);
    }
}

結果: 期待される出力は「987.65」です。

この書き方なら、丸めモードがRoundingMode.DOWNとして明確に残ります。チームで読むJavaコードでは、算術式だけで意図を推測させるより、API名とモード名で目的が分かる形のほうが扱いやすいです。

ℹ️ 補足: RoundingMode.DOWNは0方向、RoundingMode.FLOORは負の無限大方向です。正の数だけなら同じ結果でも、負の数を含むデータでは差が出ます。

まとめ

Javaの切り捨ては、Math.floor、型変換、BigDecimalDecimalFormatStreamなどを要件に応じて選びますし、これが一つの目安です。その選択では、値を変えたいのか、表示だけ整えたいのか、負の値を含むのかを先に決めると迷いにくくなります。

初心者は、Math.floorの戻り値がdoubleである点と、(int)が0方向に小数部を落とす点を押さえると基礎が固まります。一方、上級者は、丸め誤差、境界値、依存ライブラリの必要性、性能評価の方法まで含めて設計すると、保守しやすいJavaプログラミングになるのが基本です。

サンプルコードを確認するときは、期待される出力だけでなく、型、丸め方向、桁数、例外の可能性を一緒に見ます。その習慣があれば、切り捨ての方法を単なる暗記ではなく、実装要件に合わせた判断として使えるようになります。

関連記事

著者: Japanシーモア編集部

Japanシーモアは、Web/IoT/APP/SYS 分野のプログラミング情報を体系的に提供するメディアです。本記事は編集部による執筆とAI支援を組み合わせて制作し、公開前に編集部が校正しています。誤りや改善案がございましたらお問い合わせよりご連絡ください。

※本記事は実在のエンジニア複数名で構成される Japanシーモア編集部が、AI支援を活用して作成・校正・公開しています。