Sicherer Umgang mit BigDecimal in der Java-Tool-Klasse

1. Einführung in BigDecimal

Gleitkommawerte eignen sich nicht für Berechnungen, bei denen Rundungsfehler nicht toleriert werden können, wie z. B. Finanzberechnungen.Es wird daher empfohlen, BigDecimal zur Goldberechnung zu verwenden

额问题.

Die von Java im Paket java.math bereitgestellte API-Klasse BigDecimal wird verwendet, um präzise Operationen für Zahlen mit mehr als 16 signifikanten Ziffern durchzuführen. Paar

Die Präzisions-Gleitkommavariable double kann 16 signifikante Zahlen verarbeiten.

In praktischen Anwendungen müssen größere oder kleinere Zahlen bedient und verarbeitet werden. float und double können nur für wissenschaftliche Berechnungen oder verwendet werden

Es handelt sich um eine technische Berechnung, und java.math.BigDecimal wird in kommerziellen Berechnungen verwendet.

Was BigDecimal erstellt, ist ein Objekt. Wir können an seinem Objekt keine direkten mathematischen Berechnungen durchführen, indem wir herkömmliche arithmetische Operatoren wie +, -, *, / usw. verwenden.

Operation, und die entsprechende Methode muss aufgerufen werden.

Die Parameter in der Methode müssen ebenfalls BigDecimal-Objekte sein. Der Konstruktor ist eine spezielle Methode einer Klasse, die speziell zum Erstellen von Objekten verwendet wird, insbesondere mit

Ein Objekt mit Parametern.

Hintergrund:Manche Leute haben wenig Kontakt mit BigDecimal und verwenden es kaum und haben Probleme mit gängigen Multiplikations- und Divisionsberechnungen, deshalb kapseln sie es

Bequeme und effiziente Nutzung, wodurch unnötige Fehlerverarbeitungszeit reduziert wird.

2. BigDecimal-Werkzeugklasse

package com.utils;

import org.springframework.util.StringUtils;

import java.math.BigDecimal;

/**
 * BigDecimal工具类
 *
 * 浮点数值不适用于无法接受舍入误差的计算当中,比如金融计算,所以建议用BigDecimal计算金额问题。
 *
 * 背景:有些人对BigDecimal接触很少、用得少,对常见的乘法、除法计算有问题,所以封装一下方便高效运用,减少不必要的bug处理时间。
 *
 * Java在java.math包中提供的API类BigDecimal,用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数。
 *
 * 在实际应用中,需要对更大或者更小的数进行运算和处理。float和double只能用来做科学计算或者是工程计算,在商业计算中要用java.math.BigDecimal。
 *
 * BigDecimal所创建的是对象,我们不能使用传统的+、-、*、/等算术运算符直接对其对象进行数学运算,而必须调用其相对应的方法。
 *
 * 方法中的参数也必须是BigDecimal的对象。构造器是类的特殊方法,专门用来创建对象,特别是带有参数的对象。
 *
 */
public class BigDecimalUtil {
    /**
     * 默认运算精度
     */
    private static final int DEFAULT_DIV_SCALE = 10;

    /**
     * 提供精确的加法运算
     *
     * @param v1
     * @param v2
     * @return 两个参数的和
     */
    public static double add(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));

        return b1.add(b2).doubleValue();
    }

    /**
     * 提供精确的加法运算
     *
     * @param v1
     * @param v2
     * @param scale 表示需要精确到小数点以后几位。
     * @return 两个参数数学加和,以字符串格式返回
     */
    public static double add(double v1, double v2, int scale) {
        return round(add(v1, v2), 2);
    }

    /**
     * 提供精确的加法运算
     *
     * @param v1
     * @param v2
     * @return 两个参数数学加和,以字符串格式返回
     */
    public static String add(String v1, String v2) {
        if (StringUtils.isEmpty(v1)) v1 = "0";
        if (StringUtils.isEmpty(v2)) v2 = "0";

        BigDecimal b1 = new BigDecimal(v1);

        BigDecimal b2 = new BigDecimal(v2);

        return b1.add(b2).toString();
    }

    /**
     * 提供精确的加法运算
     *
     * @param v1
     * @param v2
     * @param scale 表示需要精确到小数点以后几位。
     * @return 两个参数数学加和,以字符串格式返回
     */

    public static String add(String v1, String v2, int scale) {
        if (StringUtils.isEmpty(v1)) v1 = "0";
        if (StringUtils.isEmpty(v2)) v2 = "0";
        return round(add(v1, v2), scale);
    }

    /**
     * 提供精确的减法运算
     *
     * @param v1
     * @param v2
     * @return 两个参数的差
     */

    public static double subtract(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));

        BigDecimal b2 = new BigDecimal(Double.toString(v2));

        return b1.subtract(b2).doubleValue();
    }

    /**
     * 提供精确的减法运算
     *
     * @param v1
     * @param v2
     * @param scale 表示需要精确到小数点以后几位。
     * @return 两个参数的差
     */
    public static double subtract(double v1, double v2, int scale) {
        return round(subtract(v1, v2), scale);
    }

    /**
     * 提供精确的减法运算
     *
     * @param v1
     * @param v2
     * @return 两个参数数学差,以字符串格式返回
     */
    public static String subtract(String v1, String v2) {
        if (StringUtils.isEmpty(v1)) v1 = "0";
        if (StringUtils.isEmpty(v2)) v2 = "0";

        BigDecimal b1 = new BigDecimal(v1);

        BigDecimal b2 = new BigDecimal(v2);

        return b1.subtract(b2).toString();
    }

    /**
     * 提供精确的减法运算
     *
     * @param v1
     * @param v2
     * @param scale 表示需要精确到小数点以后几位。
     * @return 两个参数数学差,以字符串格式返回
     */

    public static String subtract(String v1, String v2, int scale) {
        return round(subtract(v1, v2), 2);
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param v1
     * @param v2
     * @param scale 表示需要精确到小数点以后几位。
     * @return 两个参数的积
     */

    public static double multiply(double v1, double v2, int scale) {
        return round(multiply(v1, v2), scale);
    }

    /**
     * 提供精确的乘法运算。
     *
     * @param v1
     * @param v2
     * @return 两个参数的积
     */

    public static double multiply(double v1, double v2) {
        BigDecimal b1 = new BigDecimal(Double.toString(v1));

        BigDecimal b2 = new BigDecimal(Double.toString(v2));

        return b1.multiply(b2).doubleValue();
    }

    /**
     * 提供精确的乘法运算
     *
     * @param v1
     * @param v2
     * @param scale 表示需要精确到小数点以后几位。
     * @return 两个参数的数学积,以字符串格式返回
     */
    public static String multiply(String v1, String v2, int scale) {
        return round(multiply(v1, v2), scale);
    }

    /**
     * 提供精确的乘法运算
     *
     * @param v1
     * @param v2
     * @return 两个参数的数学积,以字符串格式返回
     */
    public static String multiply(String v1, String v2) {
        if (StringUtils.isEmpty(v1)) v1 = "0";
        if (StringUtils.isEmpty(v2)) v2 = "0";

        BigDecimal b1 = new BigDecimal(v1);

        BigDecimal b2 = new BigDecimal(v2);

        return b1.multiply(b2).toString();
    }

    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
     * <p>
     * 小数点以后10位,以后的数字四舍五入,舍入模式采用ROUND_HALF_EVEN
     *
     * @param v1
     * @param v2
     * @return 两个参数的商
     */
    public static double divide(double v1, double v2) {
        return divide(v1, v2, DEFAULT_DIV_SCALE);
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * <p>
     * 定精度,以后的数字四舍五入。舍入模式采用ROUND_HALF_EVEN
     *
     * @param v1
     * @param v2
     * @param scale 表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double divide(double v1, double v2, int scale) {
        return divide(v1, v2, scale, BigDecimal.ROUND_HALF_EVEN);
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * <p>
     * 定精度,以后的数字四舍五入。舍入模式采用用户指定舍入模式
     *
     * @param v1
     * @param v2
     * @param scale      表示需要精确到小数点以后几位
     * @param round_mode 表示用户指定的舍入模式
     * @return 两个参数的商
     */
    public static double divide(double v1, double v2, int scale, int round_mode) {
        if (scale < 0) {
            throw new IllegalArgumentException("小数点后保留几位必须整数或0");
        }

        BigDecimal b1 = new BigDecimal(Double.toString(v1));

        BigDecimal b2 = new BigDecimal(Double.toString(v2));

        return b1.divide(b2, scale, round_mode).doubleValue();
    }

    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
     * <p>
     * 小数点以后10位,以后的数字四舍五入,舍入模式采用ROUND_HALF_EVEN
     *
     * @param v1
     * @param v2
     * @return 两个参数的商,以字符串格式返回
     */
    public static String divide(String v1, String v2) {
        if (StringUtils.isEmpty(v1)) v1 = "0";
        if (StringUtils.isEmpty(v2) || Double.parseDouble(v2) == 0) v2 = "1";

        return divide(v1, v2, DEFAULT_DIV_SCALE);
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * <p>
     * 定精度,以后的数字四舍五入。舍入模式采用ROUND_HALF_EVEN
     *
     * @param v1
     * @param v2
     * @param scale 表示需要精确到小数点以后几位
     * @return 两个参数的商,以字符串格式返回
     */
    public static String divide(String v1, String v2, int scale) {
        if (StringUtils.isEmpty(v2) || Double.parseDouble(v2) == 0) v2 = "1";
        return divide(v1, v2, scale, BigDecimal.ROUND_HALF_EVEN);
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * <p>
     * 定精度,以后的数字四舍五入。舍入模式采用用户指定舍入模式
     *
     * @param v1
     * @param v2
     * @param scale      表示需要精确到小数点以后几位
     * @param round_mode 表示用户指定的舍入模式
     * @return 两个参数的商,以字符串格式返回
     */
    public static String divide(String v1, String v2, int scale, int round_mode) {
        if (scale < 0) {
            throw new IllegalArgumentException("小数点后保留几位必须整数或0");
        }

        BigDecimal b1 = new BigDecimal(v1);

        BigDecimal b2 = new BigDecimal(v2);

        return b1.divide(b2, scale, round_mode).toString();
    }

    /**
     * 提供精确的小数位四舍五入处理,舍入模式采用ROUND_HALF_EVEN
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale) {
        return round(v, scale, BigDecimal.ROUND_HALF_EVEN);

    }

    /**
     * 提供精确的小数位四舍五入处理
     *
     * @param v          需要四舍五入的数字
     * @param scale      小数点后保留几位
     * @param round_mode 指定的舍入模式
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale, int round_mode) {
        if (scale < 0) {
            throw new IllegalArgumentException("小数点后保留几位必须整数或0");
        }

        BigDecimal b = new BigDecimal(Double.toString(v));

        return b.setScale(scale, round_mode).doubleValue();
    }

    /**
     * 提供精确的小数位四舍五入处理,舍入模式采用ROUND_HALF_EVEN
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果,以字符串格式返回
     */
    public static String round(String v, int scale) {
        return round(v, scale, BigDecimal.ROUND_HALF_EVEN);
    }

    /**
     * 提供精确的小数位四舍五入处理
     *
     * @param v          需要四舍五入的数字
     * @param scale      小数点后保留几位
     * @param round_mode 指定的舍入模式
     * @return 四舍五入后的结果,以字符串格式返回
     */
    public static String round(String v, int scale, int round_mode) {
        if (scale < 0) {
            throw new IllegalArgumentException("小数点后保留几位必须整数或0");
        }

        BigDecimal b = new BigDecimal(v);

        return b.setScale(scale, round_mode).toString();
    }
}

Supongo que te gusta

Origin blog.csdn.net/qq_30713721/article/details/134795581
Recomendado
Clasificación