El uso de BigDecimal en Java

inserte la descripción de la imagen aquí

1. Descripción general de BigDecimal

La clase API BigDecimal proporcionada por Java en el paquete java.math se usa para realizar operaciones precisas en números con más de 16 dígitos efectivos. La variable de coma flotante de doble precisión double puede manejar 16 dígitos significativos, pero en aplicaciones prácticas, puede ser necesario realizar operaciones y procesamiento en números más grandes o más pequeños.

En general, podemos usar Float y Double directamente para aquellos números que no necesitan una precisión de cálculo precisa, pero Double.valueOf(String) y Float.valueOf(String) perderán precisión. Entonces, en desarrollo, si necesitamos resultados de cálculo precisos, debemos usar la clase BigDecimal para operar.

​ Lo que crea BigDecimal es un objeto, por lo que no podemos usar operadores aritméticos tradicionales como +, -, *, / para realizar directamente operaciones matemáticas en su objeto, sino que debemos llamar a su método correspondiente. Los parámetros del método también deben ser objetos BigDecimal. Un constructor es un método especial de una clase diseñado para crear objetos, especialmente objetos con parámetros.

Dos, BigDecimal constructor de uso común

2.1 Constructores de uso común

  1. BigDecimal(int) : Crea un objeto con el valor entero especificado por el parámetro
  2. BigDecimal(doble) : Crea un objeto con el valor doble especificado por el parámetro
  3. BigDecimal(largo): crea un objeto con el valor entero largo especificado por el parámetro
  4. BigDecimal(String) : Crea un objeto con el valor numérico especificado por el parámetro expresado como una cadena (recomendado)

2.2, utilice el análisis de problemas

Casos de uso:

BigDecimal a =new BigDecimal(0.1);
System.out.println("a values is:"+a);
System.out.println("=====================");
BigDecimal b =new BigDecimal("0.1");
System.out.println("b values is:"+b);

resultado:

a values is:0.1000000000000000055511151231257827021181583404541015625
=====================
b values is:0.1

Análisis de causa:

1) El resultado de un constructor cuyo tipo de parámetro es doble es algo impredecible. Uno podría pensar que escribir newBigDecimal(0.1) en Java crea un BigDecimal igual a exactamente 0.1 (el valor sin escalar de 1, que tiene una escala de 1), pero en realidad es igual a 0.1000000000000000055511151231257827021181583404541015625. Esto se debe a que 0.1 no se puede representar exactamente como un doble (o, para el caso, como una fracción binaria de longitud finita). Por lo tanto, el valor pasado al constructor no será exactamente igual a 0.1 (aunque aparentemente igual a ese valor).

2) El constructor String es completamente predecible: escribir newBigDecimal("0.1") creará un BigDecimal que es exactamente igual al 0.1 esperado. Por lo tanto, en comparación, generalmente se recomienda utilizar primero el método de construcción String.

3) Cuando se debe usar double como fuente de BigDecimal, tenga en cuenta que este constructor proporciona una conversión exacta; no proporciona el mismo resultado que usar primero el método Double.toString(double) y luego usar la construcción BigDecimal(String ). método para convertir doble a String. Para obtener ese resultado, use el método static valueOf(double).

3. Explicación detallada de los métodos comunes de BigDecimal

3.1 Métodos comunes

  1. add(BigDecimal) : Agrega los valores en el objeto BigDecimal y devuelve el objeto BigDecimal
  2. subtract(BigDecimal) : Resta los valores en el objeto BigDecimal y devuelve el objeto BigDecimal
  3. multiplicar(BigDecimal) : Multiplica los valores en el objeto BigDecimal y devuelve el objeto BigDecimal
  4. divide(BigDecimal) : divide los valores en el objeto BigDecimal y devuelve el objeto BigDecimal
  5. toString() : Convierte el valor en el objeto BigDecimal a una cadena
  6. doubleValue() : convierte el valor del objeto BigDecimal en un número de doble precisión
  7. floatValue() : convierte el valor en el objeto BigDecimal en un número de precisión simple
  8. longValue() : convierte el valor del objeto BigDecimal en un entero largo
  9. intValue() : Convierte el valor en el objeto BigDecimal a un número entero

3.2, comparación de tamaño BigDecimal

El método compareTo de bigdemical generalmente se usa para comparar el tamaño de BigDecimal en java

int a = bigdemical.compareTo(bigdemical2)

Análisis de resultados de devolución:

  • a = -1, lo que indica que bigdemical es más pequeño que bigdemical2;
  • a = 0, lo que indica que bigdemical es igual a bigdemical2;
  • a = 1, lo que indica que bigdemical es mayor que bigdemical2;

Ejemplo: a es mayor o igual que b:

 BigDecimal decimal = new BigDecimal("0.0459674");
 BigDecimal divide = decimal.divide(new BigDecimal("0.3"),2);  //精确两位小数
if (decimal.compareTo(divide)>=0){
    
    
    System.out.println(decimal+"大于等于"+divide);
}else{
    
    
    System.out.println(decimal+"小于"+divide);
}

Cuatro, formato BigDecimal

Dado que el método format() de la clase NumberFormat puede usar objetos BigDecimal como sus parámetros, BigDecimal se puede usar para controlar el formato de valores de moneda más allá de 16 dígitos significativos, valores porcentuales y valores generales.

Tome el uso de BigDecimal para dar formato a la moneda y los porcentajes como ejemplo. Primero, cree un objeto BigDecimal, realice operaciones aritméticas BigDecimal, establezca respectivamente referencias al formato de moneda y porcentaje, y finalmente use el objeto BigDecimal como un parámetro del método format() para generar su valor de moneda y porcentaje con formato.

NumberFormat currency = NumberFormat.getCurrencyInstance(); //建立货币格式化引用
NumberFormat percent = NumberFormat.getPercentInstance();  //建立百分比格式化引用
percent.setMaximumFractionDigits(3); //百分比小数点最多3位
BigDecimal loanAmount = new BigDecimal("15000.48"); //贷款金额
BigDecimal interestRate = new BigDecimal("0.008"); //利率
BigDecimal interest = loanAmount.multiply(interestRate); //相乘
System.out.println("贷款金额:\t" + currency.format(loanAmount));
System.out.println("利率:\t" + percent.format(interestRate));
System.out.println("利息:\t" + currency.format(interest));

resultado:

贷款金额:15,000.48 利率: 0.8% 利息:120.00

5. Excepciones comunes de BigDecimal

Ocurrió una excepción durante la división.

java.lang.ArithmeticException: Expansión decimal sin terminación; ningún resultado decimal representable exacto

Análisis de causa:

Al dividir por el método de división de BigDecimal, cuando no hay división de enteros y ocurre un ciclo infinito de decimales, se generará una excepción: java.lang.ArithmeticException: Expansión decimal sin terminación, sin resultado decimal representable exacto.

Solución:

divide方法设置精确的小数点,如:divide(xxxxx,2)

6. Resumen de BigDecimal

Utilice BigDecimal cuando se requieran cálculos decimales precisos. El rendimiento de BigDecimal es peor que el de double y float, especialmente cuando se trata de operaciones grandes y complejas. Por lo tanto, no es necesario usar BigDecimal para cálculos generales de precisión.

Intente usar constructores cuyo tipo de parámetro sea String.

BigDecimal es inmutable y se generará un nuevo objeto cada vez que se realicen las cuatro operaciones aritméticas, así que recuerde guardar el valor después de la operación al realizar sumas, restas, multiplicaciones y divisiones.

Recomendación de herramienta

package com.aio.util;

import java.math.BigDecimal;
/**
 * @author:qi
 * @creattime:2022-04-28 15:10
 * 用于通过BigDecimal对象高精度计算
 */
public class ArithmeticUtils {
    
    

    //默认除法运算精度
    private static final int DEF_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 加数
     * @return 两个参数的和
     */
    public static BigDecimal add(String v1, String v2) {
    
    
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.add(b2);
    }

    /**
     * 提供精确的加法运算
     *
     * @param v1    被加数
     * @param v2    加数
     * @param scale 保留scale 位小数
     * @return 两个参数的和
     */
    public static String add(String v1, String v2, int scale) {
    
    
        if (scale < 0) {
    
    
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.add(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的减法运算
     *
     * @param v1 被减数
     * @param v2 减数
     * @return 两个参数的差
     */
    public static double sub(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 减数
     * @return 两个参数的差
     */
    public static BigDecimal sub(String v1, String v2) {
    
    
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.subtract(b2);
    }

    /**
     * 提供精确的减法运算
     *
     * @param v1    被减数
     * @param v2    减数
     * @param scale 保留scale 位小数
     * @return 两个参数的差
     */
    public static String sub(String v1, String v2, int scale) {
    
    
        if (scale < 0) {
    
    
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.subtract(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的乘法运算
     *
     * @param v1 被乘数
     * @param v2 乘数
     * @return 两个参数的积
     */
    public static double mul(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 乘数
     * @return 两个参数的积
     */
    public static BigDecimal mul(String v1, String v2) {
    
    
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.multiply(b2);
    }

    /**
     * 提供精确的乘法运算
     *
     * @param v1    被乘数
     * @param v2    乘数
     * @param scale 保留scale 位小数
     * @return 两个参数的积
     */
    public static double mul(double v1, double v2, int scale) {
    
    
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return round(b1.multiply(b2).doubleValue(), scale);
    }

    /**
     * 提供精确的乘法运算
     *
     * @param v1    被乘数
     * @param v2    乘数
     * @param scale 保留scale 位小数
     * @return 两个参数的积
     */
    public static String mul(String v1, String v2, int scale) {
    
    
        if (scale < 0) {
    
    
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.multiply(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供(相对)精确的除法运算,当发生除不尽的情况时,精确到
     * 小数点以后10位,以后的数字四舍五入
     *
     * @param v1 被除数
     * @param v2 除数
     * @return 两个参数的商
     */


    public static double div(double v1, double v2) {
    
    
        return div(v1, v2, DEF_DIV_SCALE);
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * 定精度,以后的数字四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 表示表示需要精确到小数点以后几位。
     * @return 两个参数的商
     */
    public static double div(double v1, double v2, int scale) {
    
    
        if (scale < 0) {
    
    
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(Double.toString(v1));
        BigDecimal b2 = new BigDecimal(Double.toString(v2));
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 提供(相对)精确的除法运算。当发生除不尽的情况时,由scale参数指
     * 定精度,以后的数字四舍五入
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 表示需要精确到小数点以后几位
     * @return 两个参数的商
     */
    public static String div(String v1, String v2, int scale) {
    
    
        if (scale < 0) {
    
    
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v1);
        return b1.divide(b2, scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 提供精确的小数位四舍五入处理
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static double round(double v, int scale) {
    
    
        if (scale < 0) {
    
    
            throw new IllegalArgumentException("The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(Double.toString(v));
        return b.setScale(scale, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    /**
     * 提供精确的小数位四舍五入处理
     *
     * @param v     需要四舍五入的数字
     * @param scale 小数点后保留几位
     * @return 四舍五入后的结果
     */
    public static String round(String v, int scale) {
    
    
        if (scale < 0) {
    
    
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b = new BigDecimal(v);
        return b.setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 取余数
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 小数点后保留几位
     * @return 余数
     */
    public static String remainder(String v1, String v2, int scale) {
    
    
        if (scale < 0) {
    
    
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        return b1.remainder(b2).setScale(scale, BigDecimal.ROUND_HALF_UP).toString();
    }

    /**
     * 取余数  BigDecimal
     *
     * @param v1    被除数
     * @param v2    除数
     * @param scale 小数点后保留几位
     * @return 余数
     */
    public static BigDecimal remainder(BigDecimal v1, BigDecimal v2, int scale) {
    
    
        if (scale < 0) {
    
    
            throw new IllegalArgumentException(
                    "The scale must be a positive integer or zero");
        }
        return v1.remainder(v2).setScale(scale, BigDecimal.ROUND_HALF_UP);
    }

    /**
     * 比较大小
     *
     * @param v1 被比较数
     * @param v2 比较数
     * @return 如果v1 大于v2 则 返回true 否则false
     */
    public static boolean compare(String v1, String v2) {
    
    
        BigDecimal b1 = new BigDecimal(v1);
        BigDecimal b2 = new BigDecimal(v2);
        int bj = b1.compareTo(b2);
        boolean res;
        if (bj > 0) {
    
    
            res = true;
        }else {
    
    
            res = false;
        }
        return res;
    }
}

Supongo que te gusta

Origin blog.csdn.net/weixin_44975322/article/details/124475639
Recomendado
Clasificación