BigDecimal no mantener el valor real al ser de regresar de método Java

Bryan Douglas:

Estoy haciendo una aplicación de conversión de moneda en Java. Algunos otros StackOverflowians impresionantes me dio consejos para leer sobre BigDecimal con el fin de reemplazar el doble de solucionar los problemas de precisión.

Tengo un sistema de dos método; donde se convierte a la moneda de partida en USD, a continuación, convierte el valor en dólares de la moneda de destino.

Tenga en cuenta, mis tasas de conversión se almacenan como esto:

// Conversion Rates - START (as of October 30, 2018 @ 3:19 AM)
// Rates obtained from exchange-rates.org

//Convert to United States Dollar rates
private final BigDecimal CAD_TO_USD = new BigDecimal(0.76135);
private final BigDecimal EUR_TO_USD = new BigDecimal(1.1345);
private final BigDecimal YEN_TO_USD = new BigDecimal(0.008853);
// Conversion Rates - END

Después reemplacé mis dobles con sus respectivos BigDecimals - decidí probarlo y ver cómo funciona todo.

Mi clase probador ejecuta el método siguiente para iniciar el proceso de conversión.

public BigDecimal convert()
{
    BigDecimal value;

    value = convertToUSD(); //Converts the current currency into USD 
    value = convertFromUSD(value);  //Converts the previous USD currency value into the destination currency

    return value;
}

Cuando entro en mi variables de la muestra (que se están convirtiendo 2,78 yenes a dólares canadienses), di un paso a través del proceso y encontré que todo funciona hasta que regrese un valor.

A partir del método anteriormente mencionado, convertToUSD()se ejecuta y se codifica como sigue

private BigDecimal convertToUSD()
{
    switch (fromCurrency)
    {
        case "USD":
            return fromQuantity.multiply(new BigDecimal(1));

        case "CAD":
            return fromQuantity.multiply(CAD_TO_USD);

        case "EUR":
            return fromQuantity.multiply(EUR_TO_USD);

        case "YEN":
            return fromQuantity.multiply(YEN_TO_USD);
    }

    return new BigDecimal(0);
}

Todos los valores se transmiten en forma correcta, los pasos a través hasta el tamaño adecuado ( "YEN"), y el panel de muestra variables que el "fromQuantity" BigDecimal tiene un valor de 278 intCompact (que tiene sentido para mí)

introducir descripción de la imagen aquí

Tan pronto como los retornos de punto de interrupción volver al método "convertir", se pone todo en mal estado. En lugar de devolver el 2.78 * 0.008853 = 0.0246, devuelve -9223372036854775808.

introducir descripción de la imagen aquí

Esto hace que todos los otros cálculos para producir y error.

Soy nuevo en el uso BigDecimal, así que puede estar cometiendo un error obvio completa; pero estoy feliz de aprender, así que buscó el consejo de ustedes :)

Cualquier ayuda se aprecia.

Albahaca Bourque:

tl; dr

Uso String, no doubleliterales.

new BigDecimal( "2.78" )           // Pass "2.78" not 2.78
.multiply(
    new BigDecimal( "0.008853" )   // Pass "0.008853" not 0.008853
)
.toString()

0.02461134

No pase tipos de coma flotante

El punto de la BigDecimalclase es para evitar las imprecisiones inherentes que se encuentran en coma flotante tecnología. Tipos de coma flotante como float/ Floaty double/ Doublecomercio de distancia precisión para la velocidad de ejecución. Por el contrario, BigDecimales lento pero preciso.

Tu codigo:

new BigDecimal( 0.76135 )
new BigDecimal( 1.1345 )
new BigDecimal( 0.008853 )

... está pasando un doubleliteral primitivo. Durante la compilación, el texto que ha escrito 0.76135se analiza como un número, específicamente como double(un valor de coma flotante de 64 bits). En ese momento usted ha introducido imprecisiones inherentes a este tipo. En otras palabras, el doubleproducir a partir de 0.76135ya no puede ser exactamente 0.76135.

Vamos a volcar sus BigDecimalcasos inmediatamente después de creación de instancias.

System.out.println( new BigDecimal( 0.76135 ) );    // Passing a `double` primitive.
System.out.println( new BigDecimal( 1.1345 ) );
System.out.println( new BigDecimal( 0.008853 ) );

0,7613499999999999712230192017159424722194671630859375

1,13450000000000006394884621840901672840118408203125

0,0088529999999999997584154698415659368038177490234375

Así, mediante la creación de doublevalores numéricos, se invocó la tecnología de punto flotante, y se presentó inexactitudes.

Use cuerdas

¿La solución? Trabajar con cadenas, evitando el doubletipo totalmente.

Ponga un poco de comillas dobles alrededor de esas entradas , y voila .

System.out.println( new BigDecimal( "0.76135" ) );  // Passing a `String` object.
System.out.println( new BigDecimal( "1.1345" ) );
System.out.println( new BigDecimal( "0.008853" ) );

0.76135

1.1345

0.008853

Ejemplo

Que esperaba 2.78 * 0.008853 = 0.0246. Vamos a intentarlo.

BigDecimal x = new BigDecimal( "2.78" );
BigDecimal y = new BigDecimal( "0.008853" );
BigDecimal z = x.multiply( y );
System.out.println( x + " * " + y + " = " + z );

2,78 * 0,008853 = 0,02461134

A continuación, debe estudiar hasta en el redondeo y truncamiento con BigDecimal. Ya cubiertas muchas veces en desbordamiento de pila.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=185740&siteId=1
Recomendado
Clasificación