Comparando Double con BigDecimal

1. Operaciones exactas de punto flotante: 

En Java, a veces se requieren datos precisos para garantizar la precisión del valor, y el problema se puede encontrar proporcionando un ejemplo primero:

public class FloatNumberTester {  
    public static void main(String args[]){  
        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);  
    }  
}  

De acuerdo con nuestras expectativas, cuál debería ser el resultado anterior, pero mirando la salida encontraremos el problema:

0.060000000000000005  
0.5800000000000001  
401.49999999999994  
1.2329999999999999  

En este caso, el problema es relativamente serio, si usamos una transacción de 123,3 yuanes, la computadora rechaza la transacción debido a 1,2329999999999999, que es muy diferente de la situación real.

2, redondeando: 

Otro problema computacional es el redondeo. Pero el cálculo de Java en sí mismo no puede admitir el redondeo, como: 

public class GetThrowTester {  
    public static void main(String args[]){  
        System.out.println(4.015 * 100.0);  
    }  
}  

Esta salida es: 

401.49999999999994 

Entonces encontrará que esta situación no garantiza el redondeo, si desea redondear, solo hay un método 
java.text.DecimalFormat:

import java.text.DecimalFormat;  
public class NumberFormatMain {  
    public static void main(String args[]){  
        System.out.println(new DecimalFormat("0.00").format(4.025));  
        System.out.println(new DecimalFormat("0.00").format(4.024));  
    }  
}  

La salida del código anterior es: 

4.02   
4.02   

¿Encontraste un problema? Debido al modo de redondeo utilizado por DecimalFormat, consulte el final de este artículo para obtener detalles sobre los modos de redondeo. 

3. Salida de punto flotante: 

Los valores de coma flotante de Java se convierten automáticamente a notación científica cuando son mayores que 9999999. 0. Eche un vistazo al siguiente ejemplo:

public class FloatCounter {  
    public static void main(String args[]){  
        System.out.println(9969999999.04);  
        System.out.println(199999999.04);  
        System.out.println(1000000011.01);  
        System.out.println(9999999.04);  
    }  
}  

La salida es:

9.96999999904E9   
1.9999999904E8   
1.00000001101E9   
9999999.04  

Pero a veces no necesitamos notación científica, sino conversión a cadena, por lo que esto puede ser un poco engorroso. 

Resumir:

Por lo tanto, en el proyecto, trate de no usar tipos de datos básicos como double y long y sus clases contenedoras para las operaciones de tipos de punto flotante y enteros grandes, en su lugar, use los tipos numéricos grandes como BigDecimal y BigInteger provistos en Java. 
Pero aquí hay una descripción especial de la diferencia entre los dos constructores de la clase BigDecimal, ellos son:
new BigDecimal(String val ) y new BigDecimal(double val ) Veamos
primero el ejemplo:

public class BigDecimalMain {  
    public static void main(String args[]){  
        System.out.println(new BigDecimal(123456789.01).toString());  
        System.out.println(new BigDecimal("123456789.01").toString());  
    }  
}  

La salida es sorprendente una vez, y la diferencia entre los dos es clara de un vistazo:

123456789.01000000536441802978515625   
123456789.01   

Por lo tanto, en el caso de que solo quiera usar el tipo primitivo doble para realizar cálculos relacionados y luego convertirlo al tipo BigDecimal, para evitar desviaciones en la precisión, se recomienda usar el constructor con el parámetro Tipo de cadena. es decir, nuevo BigDecimal (String val).


Introducción al modo de redondeo BigDecimal: 

  El modo de redondeo está en java.math.RoundingMode: 
RoundingMode.CEILING: El modo de redondeo para redondear hacia el infinito positivo. Si el resultado es positivo, el comportamiento de redondeo es similar a RoundingMode.UP, si el resultado es negativo, el comportamiento de redondeo es similar a RoundingMode.DOWN. Tenga en cuenta que este modo de redondeo nunca reduce el valor calculado 

escriba los datos Use el modo de redondeo TECHO para redondear un número a un dígito 
5.5
2.5
1.1
1.0
-1.0 -1 
-1.1 -1 
-1.6 -1 
-2.5 -2
-5.5 -5


RoundingMode.DOWN : Modo de redondeo para redondeo hacia cero. Nunca agregue 1 (es decir, trunque) los números que preceden a la parte descartada. Tenga en cuenta que este modo de redondeo nunca aumenta el valor absoluto del valor calculado 

escriba los datos Use el modo de redondeo ABAJO para redondear números a un dígito 
5.5
2.5
1.1
-1.0 -1 
-1.6 -1 
-2.5 -2 
-5.5 -5 


RoundingMode.FLOOR: el modo de redondeo para redondear hacia el infinito negativo. Si el resultado es positivo, el comportamiento de redondeo es similar a RoundingMode.DOWN, si el resultado es negativo, el comportamiento de redondeo es similar a RoundingMode.UP. Tenga en cuenta que este modo de redondeo nunca se suma al valor calculado  

escriba los datos Utilice el modo de redondeo FLOOR para redondear los números de entrada a un dígito 
5.5
2.3
1.6
1.0
-1.1 -2 
-2.5 -3 
-5.5 -6


RoundingMode.HALF_DOWN: el modo de redondeo para redondear hacia el número más cercano o hacia abajo si la distancia entre dos números adyacentes es igual. Si la parte descartada es > 0.5, el comportamiento de redondeo es el mismo que RoundingMode.UP; de lo contrario, el comportamiento de redondeo es el mismo que RoundingMode.DOWN   

escriba los datos Redondea a un bit usando el modo de entrada HALF_DOWN 
5.5
2.5
1.6
1.0
-1.1 -1 
-1.6 -2 
-2.5 -2 
-5.5 -5 


RoundingMode.HALF_EVEN :向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向相邻的偶数舍入。如果舍弃部分左边的数字为奇数,则舍入行为同 RoundingMode.HALF_UP;如果为偶数,则舍入行为同 RoundingMode.HALF_DOWN。注意,在重复进行一系列计算时,此舍入模式可以在统计上将累加错误减到最小。此舍入模式也称为“银行家舍入法”,主要在美国使用。此舍入模式类似于 Java 中对 float 和 double 算法使用的舍入策略 

输入数字 使用HALF_EVEN舍入模式将输入舍为一位 
5.5
2.5
1.6
1.1
-1.0 -1 
-1.6 -2 
-2.5 -2 
-5.5 -6 

RoundingMode.HALF_UP :向最接近数字方向舍入的舍入模式,如果与两个相邻数字的距离相等,则向上舍入。如果被舍弃部分 >= 0.5,则舍入行为同 RoundingMode.UP;否则舍入行为同 RoundingMode.DOWN。注意,此舍入模式就是通常学校里讲的四舍五入  

输入数字 使用HALF_UP舍入模式舍入为一位数 
5.5
2.5
1.6
1.0
-1.1 -1 
-1.6 -2 
-2.5 -3 
-5.5 -6 


RoundingMode.UNNECESSARY :用于断言请求的操作具有精确结果的舍入模式,因此不需要舍入。如果对生成精确结果的操作指定此舍入模式,则抛出 ArithmeticException 

输入数字 使用UNNECESSARY模式 
5.5 抛出 ArithmeticException 
2.5 抛出 ArithmeticException 
1.6 抛出 ArithmeticException 
1.0
-1.0 -1.0 
-1.1 抛出 ArithmeticException 
-1.6 抛出 ArithmeticException 
-2.5 抛出 ArithmeticException 
-5.5 抛出 ArithmeticException

RoundingMode.UP :远离零方向舍入的舍入模式。始终对非零舍弃部分前面的数字加 1。注意,此舍入模式始终不会减少计算值的绝对值 

输入数字 使用UP舍入模式将输入数字舍入为一位数 
5.5
1.6
1.1
1.0
-1.1 -2 
-1.6 -2 
-2.5 -3 
-5.4 -6


 

import  java.math.BigDecimal;   
import  java.text.DecimalFormat;   
/**  
 *使用舍入模式的格式化操作  
 **/   
public class   DoubleFormat {   
    public static void  main(String  args[]){   
        DoubleFormat format =  new  DoubleFormat();   
        System.out .println(format.doubleOutPut(12.345, 2));   
        System.out .println(format.roundNumber(12.335, 2));   
    }   
    public   String  doubleOutPut(double  v,Integer num){   
        if ( v == Double.valueOf(v).intValue()){   
            return  Double.valueOf(v).intValue() +  "" ;   
        }else {   
            BigDecimal b =  new  BigDecimal(Double.toString(v));   
            return  b.setScale(num,BigDecimal.ROUND_HALF_UP ).toString();   
        }   
    }   
    public   String  roundNumber(double  v,int  num){   
        String  fmtString =  "0000000000000000" ;  //16bit   
        fmtString = num>0 ?  "0."   + fmtString.substring(0,num):"0" ;   
        DecimalFormat dFormat =  new  DecimalFormat(fmtString);   
        return  dFormat.format(v);   
    }   
}

这段代码的输出为: 

12.35   
12.34  

转载于:Double与BigDecimal 比较 - 兔老霸夏 - 博客园

Supongo que te gusta

Origin blog.csdn.net/weixin_42602900/article/details/123234378
Recomendado
Clasificación