Actualmente tengo este método:¿Cómo verificar si un doble tiene como máximo n lugares decimales?
static boolean checkDecimalPlaces(double d, int decimalPlaces){
if (d==0) return true;
double multiplier = Math.pow(10, decimalPlaces);
double check = d * multiplier;
check = Math.round(check);
check = check/multiplier;
return (d==check);
}
Pero este método falla por checkDecmialPlaces(649632196443.4279, 4)
probablemente porque hago matemáticas de base 10 en una base numérica 2.
Entonces, ¿cómo se puede hacer esta verificación correctamente?
Pensé en obtener una representación de cadena del doble valor y luego comprobarlo con una expresión regular, pero eso me pareció extraño.
EDITAR: Gracias por todas las respuestas. Hay casos en los que realmente tener una doble y para aquellos casos que implementan los siguientes:
private static boolean checkDecimalPlaces(double d, int decimalPlaces) {
if (d == 0) return true;
final double epsilon = Math.pow(10.0, ((decimalPlaces + 1) * -1));
double multiplier = Math.pow(10, decimalPlaces);
double check = d * multiplier;
long checkLong = (long) Math.abs(check);
check = checkLong/multiplier;
double e = Math.abs(d - check);
return e < epsilon;
}
he cambiado el round
a un truncamiento. Parece que el cálculo realizado en round
aumenta demasiado la imprecisión. Al menos en el caso de prueba que falla.
Como algunos de ustedes han señalado si podía llegar a la entrada 'real' de la cadena que debe utilizar BigDecimal
para comprobar y por lo que he hecho:
BigDecimal decimal = new BigDecimal(value);
BigDecimal checkDecimal = decimal.movePointRight(decimalPlaces);
return checkDecimal.scale() == 0;
El valor double
recibo viene de la API de Apache POI que lee los archivos de Excel. Hice algunas pruebas y descubrió que aunque el API devuelve double
valores de celdas numéricas puedo conseguir una representación exacta cuando inmediatamente formato que double
con el DecimalFormat
:
DecimalFormat decimalFormat = new DecimalFormat();
decimalFormat.setMaximumIntegerDigits(Integer.MAX_VALUE);
// don't use grouping for numeric-type cells
decimalFormat.setGroupingUsed(false);
decimalFormat.setDecimalFormatSymbols(new DecimalFormatSymbols(Locale.US));
value = decimalFormat.format(numericValue);
Esto también funciona para valores que no pueden estar representado exactamente en formato binario.
"correcta" no significa mucho aquí. Sus números decimales aleatorios no tienen representaciones binarias exactas. Está buscando un número decimal que esté "lo suficientemente cerca" para que a las personas les guste la versión decimal del valor binario. ¿Qué tan cerca está lo suficientemente cerca? –