¿Por qué Java no ingresa a este bloque de código?

CorePress2024-01-24  12

Esta pregunta ya tiene respuestas aquí: ¿Están rotas las matemáticas de punto flotante?

(34 respuestas)

Cerrado

hace 2 años

.

Mi tarea es comparar dos números y devolver verdadero si son iguales por tres decimales. Cuando imprimo el valor de diff es 0.0001, pero aún no ingresa al bloque if(diff <= 0.0001).

    public class DecimalComparator {
    public static boolean areEqualByThreeDecimalPlaces(double num1, double num2) {
        double diff = Math.abs(num1 - num2);

        System.out.printf("%f", diff);
        if(diff <= 0.0001) {
            return true;
        } else {

            return false;
        }
    }

    public static void main(String[] args) {
        boolean test = areEqualByThreeDecimalPlaces(3.1756, 3.1755);
        System.out.println(test);

        test = areEqualByThreeDecimalPlaces(3.176, 3.175);
        System.out.println(test);
    }
}
    

Si escribe System.out.println(diff); en lugar de System.out.printf("%f", diff); obtendrá 1.0000000000021103E-4: el valor de diff no es 0.0001, simplemente no está imprimiendo su valor exacto.

-kaya3

27 de marzo de 2021 a las 2:20

@AbhijitSarkar La pregunta afirma que 3.1756 - 3.1755 es igual a 0.0001, lo cual no es así, porquese de imprecisión aritmética de punto flotante. La respuesta que usted mismo publicó realmente no tiene sentido en ninguna interpretación de la pregunta.

-kaya3

27 de marzo de 2021 a las 2:33



------------------------------------

Cuando necesite precisión arbitraria, utilice BigDecimal. Además, tu número mágico debe ser 0,001 con tres decimales. Me gusta,

public static boolean areEqualByThreeDecimalPlaces(double num1, double num2) {
    return new BigDecimal(num1).subtract(new BigDecimal(num2)).abs()
            .compareTo(new BigDecimal(0.001)) <= 0;
}

public static void main(String[] args) {
    System.out.println(areEqualByThreeDecimalPlaces(3.1756, 3.1755));
    System.out.println(areEqualByThreeDecimalPlaces(3.176, 3.175));
}

Salidas

true
false



------------------------------------

Aunque creo que @Elliot Frisch tiene el mejor enfoque de Java,Siempre es difícil saber si uno debe introducir conceptos más allá de los primitivos estándar para lo que parece ser tarea.

Como alternativa, sabiendo que el valor deseado es de 3 decimales, el problema puede reconceptualizarse multiplicando por 1000 y usando un int.

Ejemplo:

    public static boolean areEqualByThreeDecimalPlaces(double num1, double num2) {
        final int mult = 1000;
        int i1 = (int)(num1 * mult);
        int i2 = (int)(num2 * mult);
        
        return (Math.abs(i1 - i2)) == 0;
    }

El resultado muestra el verdadero y el falso esperados para los casos de prueba.

Solo un enfoque alternativo a considerar si no se puede cambiar al uso de otras clases de Java.

Su guía para un futuro mejor - libreflare
Su guía para un futuro mejor - libreflare