Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

316
Vistas
¿Por qué se implementa Math.min() double/float de Java de esta manera?

Estaba revisando algunas cosas en el código fuente de java.lang.Math y noté que mientras Math.min(int, int) (o su contraparte larga) se implementa de esta manera:

 public static int min(int a, int b) { return a <= b ? a : b; }

Y esto tiene mucho sentido para mí y es lo mismo que yo haría. Sin embargo, la implementación doble/flotante es esta:

 public static float min(float a, float b) { if (a != a) { return a; } else if (a == 0.0F && b == 0.0F && (long)Float.floatToRawIntBits(b) == negativeZeroFloatBits) { return b; } else { return a <= b ? a : b; } }

Estoy completamente estupefacto. ¿Comparando a consigo mismo? ¿Para qué sirve el segundo cheque? ¿Por qué no se implementa de la misma manera que la versión int/long?

over 4 years ago · Santiago Trujillo
4 Respuestas
Responde la pregunta

0

Los números de punto flotante son mucho más complicados que los valores enteros.

Para este caso específico, dos distinciones son importantes:

  • NaN es un valor válido para float y double que representa "no un número" y se comporta de forma extraña. Es decir, no se compara igual a sí mismo.
  • Los números de coma flotante pueden diferenciar entre 0,0 y -0,0. Un cero negativo posiblemente podría ser útil cuando calcula el límite de alguna función. Distinguir si un límite se aproxima a 0 desde la dirección positiva o negativa podría ser beneficioso.

Entonces esta parte:

 if (a != a) { return a; }

asegura que se devuelva NaN si a es NaN (si a no es NaN , pero b sí lo es, entonces la verificación "normal" más adelante devolverá b , es decir, NaN , por lo que no se necesita una verificación explícita para este caso). Este es un patrón común: al calcular algo donde una entrada es NaN , la salida también será NaN . Dado que NaN generalmente representa algún error en el cálculo (como dividir 0 por 0), es importante que "envenene" todos los cálculos posteriores para garantizar que el error no se trague en silencio.

Esta parte:

 if (a == 0.0F && b == 0.0F && (long)Float.floatToRawIntBits(b) == negativeZeroFloatBits) { return b; }

asegura que si compara dos números de punto flotante con valor cero y b es cero negativo, se devuelve ese cero negativo (ya que -0.0 es "menor" que 0.0). De manera similar a NaN , la verificación normal devolverá correctamente a si es -0.0 b es 0.0.

over 4 years ago · Santiago Trujillo Denunciar

0

Recomiendo leer detenidamente la documentación de Math.min y también los operadores de comparación numérica en puntos flotantes. Sus comportamientos son bastante diferentes.

Partes relevantes de Math.min :

Si cualquiera de los valores es NaN, entonces el resultado es NaN. A diferencia de los operadores de comparación numérica, este método considera que el cero negativo es estrictamente menor que el cero positivo.

y de JLS §15.20.1 "Operadores de comparación numérica <, <=, > y >="

El resultado de una comparación de punto flotante, según lo determinado por la especificación del estándar IEEE 754, es:

  • Si alguno de los operandos es NaN, el resultado es falso.

  • El cero positivo y el cero negativo se consideran iguales.

Si algún argumento es NaN, Math.min elige ese, pero si algún operando es NaN, <= se evalúa como false . Es por eso que tiene que verificar si a no es igual a sí mismo; esto significaría que a es NaN. Si a no es NaN pero b sí, el último caso lo cubriría.

Math.min también considera que -0.0 es "menor que" +0.0 , pero los operadores de comparación numérica creen que son iguales. Este es el propósito de la segunda verificación.

over 4 years ago · Santiago Trujillo Denunciar

0

Puedo ayudarte en la primera comparación if (a != a) . Obviamente, esto solo analiza a , entonces, ¿en qué casos podría ser a el mínimo independientemente de b ?

Los números float se diferencian de int por tener valores especiales , por ejemplo, NAN . Y una propiedad especial de NAN es que una comparación siempre es falsa. Entonces, la primera condición devuelve a si cada operador de comparación devuelve falso en a .

La misma condición para b se puede encontrar en la última línea. Si una comparación en b siempre devuelve false, la última línea siempre devuelve b .

En la segunda condición, solo puedo adivinar que esto está relacionado con "cero negativo" y "cero positivo", otros dos valores especiales de float . Y por supuesto, un cero negativo es más pequeño que un cero positivo.

over 4 years ago · Santiago Trujillo Denunciar

0

Solo por completitud/claridad, elaboremos una tabla de todos los resultados posibles:

  • Cualquiera de a y b puede ser cualquiera

    • NaN ,
    • −0 ,
    • 0 (es decir, +0), o
    • algún otro valor distinto de NaN distinto de cero, marcado como "(otro)".

    Escribir todas las combinaciones de estos para completar, y distinguir entre números positivos y negativos para mayor claridad en algunos casos, da las 20 filas en la tabla a continuación, aunque la mayoría de ellas son sencillas y sin problemas.

  • La columna titulada "Correct min" es el valor correcto que se supone que se devolverá de acuerdo con elestándar IEEE 754 y la documentación de Java de Math.min , y la columna titulada "Naive min" es el valor que se habría devuelto si Math.min se había implementado como return a <= b ? a : b; en lugar de.

a B Mínimo correcto minuto ingenuo Notas sobre min ingenuo Ingenuo min mal?
Yaya Yaya Yaya Yaya b, ya que la comparación de NaN da falso.
Yaya −0 Yaya −0 b, ya que la comparación de NaN da falso. Incorrecto
Yaya 0 Yaya 0 b, ya que la comparación de NaN da falso. Incorrecto
Yaya (otro) Yaya (otro) b, ya que la comparación de NaN da falso. Incorrecto
−0 Yaya Yaya Yaya b, ya que la comparación de NaN da falso.
−0 −0 −0 −0 a, como −0 ≤ −0.
−0 0 −0 −0 a, como −0 ≤ 0.
−0 (otro>0) −0 −0
−0 (otro<0) (otro<0) (otro<0)
0 Yaya Yaya Yaya b, ya que la comparación de NaN da falso.
0 −0 −0 0 a, como "0 ≤ −0" según IEEE 754. Incorrecto
0 0 0 0 a, como 0 ≤ 0.
0 (otro>0) 0 0
0 (otro<0) (otro<0) (otro<0)
(otro) Yaya Yaya Yaya b, ya que la comparación de NaN da falso.
(otro<0) −0 (otro<0) (otro<0)
(otro>0) −0 −0 −0
(otro<0) 0 (otro<0) (otro<0)
(otro>0) 0 0 0
(otro) (otro) (otro) (otro)

[El "(otro)" en la última fila para "Correct min" y "Naive min" significa el mínimo correcto, en el sentido directo sin ninguna confusión debido a NaN o −0.]

Como puede ver, hay cuatro filas en la tabla anterior en las que la función ingenua daría una respuesta incorrecta:

  • tres de ellos son el caso cuando a es NaN, pero b no lo es. Para esto es el primer cheque en la función.

  • el otro es el caso en el que Java documenta que Math.min(0, -0) devuelve −0, aunque IEEE 754 trata 0 y −0 como iguales para la comparación (y, por lo tanto, la comparación "0 ≤ −0" se evalúa como cierto). Para esto es el segundo cheque en la función.

over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda