[Transferencia] ¿Cuánto sabes sobre la clase BigDecimal en Java?

prefacio

Todos sabemos que las variables de coma flotante perderán precisión al realizar los cálculos. El siguiente fragmento de código:

System.out.println(0.05 + 0.01); System.out.println(1.0 - 0.42); System.out.println(4.015 * 100); System.out.println(123.3 / 100); 输出: 0.060000000000000005 0.5800000000000001 401.49999999999994 1.2329999999999999 

Se puede ver que cuando se realizan operaciones de punto flotante en Java, habrá un problema de pérdida de precisión. Entonces, si calculamos el precio de la materia prima, habrá problemas. Es muy probable que tengamos 0,06 yuanes en nuestras manos, pero no podemos comprar una mercancía de 0,05 yuanes y una mercancía de 0,01 yuanes. Porque como se muestra arriba, la suma de los dos es 0.060000000000000005. Sin duda, este es un problema muy serio, especialmente cuando aumenta el volumen concurrente de sitios web de comercio electrónico, los problemas que surgirán serán enormes. Puede resultar en la imposibilidad de realizar un pedido o problemas con la reconciliación. Entonces podemos usar la clase BigDecimal en Java para resolver este tipo de problema.

Popularizarlo:

La precisión de float en Java es de 6-7 cifras significativas. double tiene una precisión de 15-16 dígitos.

API

Constructor:

构造器                   描述BigDecimal(int)       创建一个具有参数所指定整数值的对象。      
  BigDecimal(double) 创建一个具有参数所指定双精度值的对象。 BigDecimal(long) 创建一个具有参数所指定长整数值的对象。 BigDecimal(String) 创建一个具有参数所指定以字符串表示的数值的对象。 

función:

方法                    描述add(BigDecimal)       BigDecimal对象中的值相加,然后返回这个对象。
  subtract(BigDecimal) BigDecimal对象中的值相减,然后返回这个对象。 multiply(BigDecimal) BigDecimal对象中的值相乘,然后返回这个对象。 divide(BigDecimal) BigDecimal对象中的值相除,然后返回这个对象。 toString() 将BigDecimal对象的数值转换成字符串。 doubleValue() 将BigDecimal对象中的值以双精度数返回。 floatValue() 将BigDecimal对象中的值以单精度数返回。 longValue() 将BigDecimal对象中的值以长整数返回。 intValue() 将BigDecimal对象中的值以整数返回。 

Debido al tipo numérico general, como doble, no puede representar con precisión números con más de 16 bits.

La precisión BigDecimal también se pierde

Cuando usamos BigDecimal, solo tiene sentido usar su constructor BigDecimal(String) para crear objetos. Para otros como BigDecimal b = new BigDecimal(1), el problema de la pérdida de precisión seguirá ocurriendo. El siguiente código:

BigDecimal a = new BigDecimal(1.01); BigDecimal b = new BigDecimal(1.02); BigDecimal c = new BigDecimal("1.01"); BigDecimal d = new BigDecimal("1.02"); System.out.println(a.add(b)); System.out.println(c.add(d)); 输出: 2.0300000000000000266453525910037569701671600341796875 2.03 

Se puede ver que la pérdida de precisión BigDecimal es aún más excesiva. Sin embargo, este problema no ocurre cuando las variables que utilizan el constructor BigDecimal(String) de Bigdecimal realizan operaciones. La razón está contenida en los principios de composición de las computadoras, y su codificación determina tal resultado. long puede almacenar exactamente 19 dígitos, mientras que double solo está preparado para almacenar 16 dígitos. Debido al bit exp, el doble puede almacenar números con más de 16 bits, pero a costa de la inexactitud de bits bajos. Si necesita un almacenamiento preciso de números superiores a 19, debe usar BigInteger para guardar, por supuesto, se sacrificará algo de rendimiento. Por lo tanto, cuando generalmente usamos BigDecimal para resolver el problema de pérdida de precisión en las operaciones comerciales, al declarar un objeto BigDecimal, debemos usar su constructor cuyo parámetro es String.

Al mismo tiempo, este principio también se menciona en Eficaz Java y MySQL. float y double solo se pueden usar para cálculos científicos y de ingeniería. Usamos BigDecimal en las operaciones comerciales.

Además, también hemos dado una explicación oficial de los comentarios del código fuente. La siguiente es una parte de la explicación del comentario sobre el constructor del parámetro de tipo doble de la clase BigDecimal:

* The results of this constructor can be somewhat unpredictable.
     * One might assume that writing { 
            

El primer párrafo también deja en claro que solo puede calcular infinitamente cerca de este número, pero no puede ser exacto para este número. El segundo párrafo dice que si desea calcular este valor con precisión, debe convertir el parámetro de tipo doble a tipo Cadena. Y use el método de construcción BigDecimal(String) para construir. para obtener el resultado.

Uso correcto de BigDecimal

Además, lo que BigDecimal crea es un objeto, no podemos usar operadores aritméticos tradicionales como +, -, *, / para realizar directamente operaciones matemáticas sobre su objeto, sino que debemos llamar a su método correspondiente. Los parámetros en el método también deben ser objetos BigDecimal, como se puede ver en la API que acabamos de enumerar.

En el proceso general de desarrollo, los datos almacenados en nuestra base de datos son de tipo float y double. Es muy inconveniente continuar convirtiendo al realizar cálculos. Aquí escribí una clase de utilidad:

/**
 * @author: Ji YongGuang.
 * @date: 19:50 2017/12/14.
 */
public class BigDecimalUtil { private BigDecimalUtil() { } public static BigDecimal add(double v1, double v2) { 
                            // v1 + v2 BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.add(b2); } public static BigDecimal sub(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.subtract(b2); } public static BigDecimal mul(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); return b1.multiply(b2); } public static BigDecimal div(double v1, double v2) { BigDecimal b1 = new BigDecimal(Double.toString(v1)); BigDecimal b2 = new BigDecimal(Double.toString(v2)); // 2 = 保留小数点后两位 ROUND_HALF_UP = 四舍五入 return b1.divide(b2, 2, BigDecimal.ROUND_HALF_UP);// 应对除不尽的情况 } } 

Esta clase de herramienta proporciona operaciones básicas de suma, resta, multiplicación y división del tipo doble. Solo llámalo directamente.


Autor: HikariCP
Enlace: https://www.jianshu.com/p/c81edc59546c
Fuente: Jianshu
Los derechos de autor pertenecen al autor. Para reimpresión comercial, comuníquese con el autor para obtener autorización, para reimpresión no comercial, indique la fuente.

Supongo que te gusta

Origin blog.csdn.net/m0_53121042/article/details/114847142
Recomendado
Clasificación