La clase BigDecimaltiene algunos métodos útiles para garantizar una conversión sin pérdidas:
byteValueExact()shortValueExact()intValueExact()longValueExact()
Sin embargo, los métodos floatValueExact()y doubleValueExact()no existen.
Leí el código fuente de OpenJDK para métodos floatValue()y doubleValue(). Ambos parecen retroceder Float.parseFloat()y Double.parseDouble(), respectivamente, lo que puede devolver un infinito positivo o negativo. Por ejemplo, analizar una cadena de 10,000 9s devolverá un infinito positivo. Según tengo entendido, BigDecimalno tiene un concepto interno de infinito. Además, analizando una cadena de 100 9s como doubleda 1.0E100, que no es infinito, pero pierde precisión.
¿Qué es una implementación razonable floatValueExact()y doubleValueExact()?
Pensé en una doublesolución mediante la combinación de BigDecimal.doubleValue(), BigDecial.toString(), Double.parseDouble(String)y Double.toString(double), pero se ve desordenado. Quiero preguntar aquí porque puede (¡debe!) Haber una solución más simple.
Para ser claros, no necesito una solución de alto rendimiento.
fuente

Respuestas:
De leer los documentos , todo lo que hace con el
numTypeValueExactvariantes es verificar la existencia de una fracción o si el valor es demasiado grande para el tipo numérico y lanzar excepciones.En cuanto a
floatValue()ydoubleValue(), se está realizando una comprobación de desbordamiento similar, pero en lugar de lanzar una excepción, en su lugar, devuelveDouble.POSITIVE_INFINITYoDouble.NEGATIVE_INFINITYpara dobles yFloat.POSITIVE_INFINITYoFloat.NEGATIVE_INFINITYflotantes.Por lo tanto, la implementación más razonable (y más simple) de los
exactmétodos para flotante y doble, simplemente debe verificar si la conversión regresaPOSITIVE_INFINITYoNEGATIVE_INFINITY.Además , recuerde que
BigDecimalfue diseñado para manejar la falta de precisión que proviene del usofloatodoublepara grandes irracionales, por lo tanto, como comentó @JB Nizet , otra comprobación que puede agregar a lo anterior sería convertir o volver adoublefloatBigDecimala ver si todavía obtiene El mismo valor. Esto debería probar que la conversión fue correcta.Así es como se vería este método
floatValueExact():El uso de en
compareTolugar de loequalsanterior es intencional para no ser demasiado estricto con los controles.equalssolo se evaluará como verdadero cuando los dosBigDecimalobjetos tengan el mismo valor y escala (tamaño de la fracción de la parte decimal), mientras quecompareTopasará por alto esta diferencia cuando no importe. Por ejemplo2.0vs2.00.fuente
Float.isFinite()oFloat.isInfinite(), pero esto es opcional.:)123.456f. Supongo que esto se debe al diferente tamaño de significado (mantisa) entre el flotante de 32 bits y el doble de 64 bits. En el código anterior, consigo mejores resultados con:if (new BigDecimal(result, MathContext.DECIMAL32).equals(decimal)) {. ¿Es este un cambio razonable ... o me falta otro caso de esquina de valores de coma flotante?123.456fes conceptualmente igual que su ejemplo 1.0E100. Me sorprende que si necesita verificar que la conversión de BigDecimal -> punto flotante binario sea exacta, entonces esa necesidad es el problema; es decir, la conversión no debe contemplarse.