BigDecimal の金額を計算する 4 つの方法を共有する

基本的な紹介

金額の計算は小数点第2位で四捨五入するのが一般的ですが、自社システムの内部関数であれば金額の桁数は固定であることが多く、通常のロジックでも同じ桁数が確保されています。足し算、引き算、掛け算、割り算ですが、掛け算と割り算は比較的特殊で、小数点計算の部分ではより多くの小数点が計算される場合があります。計算された金額データを特定の値と比較する必要がある場合は、データ部分を考慮する必要があります。この状況に対処するには、データ ロジックには 2 つの一般的なタイプがあります。1 つ目は、2 つの値が一致したときに、絶対値のエラーしきい値が適用されます。許容しきい値の範囲内であれば (たとえば、 、両方の値は小数点以下 2 桁までであり、しきい値は 0.0001 に設定されています)、それらは等しいとみなされます; 2 つ目は、金額の計算プロセスで使用される計算方法を知り、統一された計算を使用することです同じ結果を計算する方法。

去年実装した機能ですが、たまたま小数点以下の桁数の計算方法が色々とあり、四捨五入、切り捨て、5組四捨五入、正負四捨五入(実際はもっとあります)、これらのデータは、該当するコードの計算方法で取得できます。今回は主に Math と BigDecimal を共有します。参考は次のとおりです。

算数

@RunWith(JUnit4.class)
public class CalculateMathTest {

    /**
     * 保留2位小数,四舍五入
     */
    @Test
    public void round() {
        System.out.println(Math.round(12345.554 * 100) / 100D);
        System.out.println(Math.round(12345.555 * 100) / 100D);
        System.out.println(Math.round(12345.556 * 100) / 100D);
    }

    /**
     * 保留2位小数,正舍负入(ceil:反过来,正入负舍)
     */
    @Test
    public void floor() {
        System.out.println(Math.floor(123.554 * 100) / 100D);
        System.out.println(Math.floor(123.555 * 100) / 100D);
        System.out.println(Math.floor(123.556 * 100) / 100D);

        System.out.println(Math.floor(-123.554 * 100) / 100D);
        System.out.println(Math.floor(-123.555 * 100) / 100D);
        System.out.println(Math.floor(-123.556 * 100) / 100D);
    }

}

小さなデモを作成しようとしましたが、数学関数クラスである Math によって提供される API は金額の計算に焦点を当てていないことがわかりました。そのため、見つかった金額計算 API は比較的小さく、金額計算は比較的役に立たないことがわかりました( (最初に100を掛けて、次に100で割って小数点以下の金額を求める)、今回の金額の4つの計算方法のうち2つを満たしているとみなすことができます。

BigDecimal

/**
 * 保留2位小数,四舍五入
 */
@Test
public void round() {
    System.out.println(new BigDecimal("12345.554").setScale(2, BigDecimal.ROUND_HALF_UP));
    System.out.println(new BigDecimal("12345.555").setScale(2, BigDecimal.ROUND_HALF_UP));
    System.out.println(new BigDecimal("12345.556").setScale(2, BigDecimal.ROUND_HALF_UP));
}
/**
 * 保留2位小数,正舍负入
 */
@Test
public void floor() {
    System.out.println(new BigDecimal("12345.554").setScale(2, BigDecimal.ROUND_FLOOR));
    System.out.println(new BigDecimal("12345.555").setScale(2, BigDecimal.ROUND_FLOOR));
    System.out.println(new BigDecimal("12345.556").setScale(2, BigDecimal.ROUND_FLOOR));
    System.out.println();
    System.out.println(new BigDecimal("-12345.554").setScale(2, BigDecimal.ROUND_FLOOR));
    System.out.println(new BigDecimal("-12345.555").setScale(2, BigDecimal.ROUND_FLOOR));
    System.out.println(new BigDecimal("-12345.556").setScale(2, BigDecimal.ROUND_FLOOR));
}
/**
 * 保留2位小数,截位法
 */
@Test
public void down() {
    System.out.println(new BigDecimal("12345.554").setScale(2, BigDecimal.ROUND_DOWN));
    System.out.println(new BigDecimal("12345.555").setScale(2, BigDecimal.ROUND_DOWN));
    System.out.println(new BigDecimal("12345.556").setScale(2, BigDecimal.ROUND_DOWN));
}
/**
 * 保留2位小数,四舍六入五成双
 */
@Test
public void even() {
    System.out.println(new BigDecimal("12345.234").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.236").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.235").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.245").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println();
    System.out.println(new BigDecimal("12345.2450").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2451").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2452").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2453").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2454").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2455").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2456").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2457").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2458").setScale(2, BigDecimal.ROUND_HALF_EVEN));
    System.out.println(new BigDecimal("12345.2459").setScale(2, BigDecimal.ROUND_HALF_EVEN));
}

その他の指示

BigDecimalは金額計算のためのさまざまなメソッドを提供しており、一部の計算ルールの実装もRoundingModeクラスで別途宣言(カプセル化)されています。50%への四捨五入は銀行間アルゴリズムとも呼ばれます。クロスすると理解しにくいです。はい、この演習では理解するために複数の出力例を取り出しました。そのため、私が整理した知識ポイントは次のとおりです。

(1) 小数点以下 2 位を維持し、少なくとも小数点以下 3 位まで正確である必要があり、小数点以下 2 位の桁上げ方法は小数点以下 3 位の値に応じて判断します。

(2) 小数点第3位が4の場合は四捨五入、6の場合は1を切り上げます。

(3) 小数点の 3 桁目が 5 で、10 進数 4 桁がない場合は、10 進数の 2 桁目を観察し、基数の場合は 1 を加え、偶数の場合は切り捨てます。

(4) 小数点第 3 桁が 5 で、小数点以下第 4 位がある場合は、小数点以下第 4 位を観察し、0 の場合は切り捨て、そうでない場合は 1 を加算します。

したがって、50 と double に丸めた出力は次のとおりです。

BigDecimal の金額を計算する 4 つの方法を共有するChen Dongdong の個人的な経験共有プラットフォームへようこそhttps://www.chendd.cn/blog/article/1649745859662635010.html 

おすすめ

転載: blog.csdn.net/haiyangyiba/article/details/130311739