Estoy volviendo a consultar una pregunta (How to test if numeric conversion will change value?) que, en lo que a mí respecta, estaba completamente resuelta. El problema era detectar cuándo un valor numérico particular sobrecargaría el tipo de número IEEE-754 de JavaScript. La pregunta anterior era usar C# y la respuesta marcada funcionó perfectamente.IEEE-754 Doble (coma flotante de 64 bits) vs. Largo (Entero de 64 bits) Revisited
Ahora estoy haciendo exactamente la misma tarea pero esta vez en Java y no funciona. AFAIK, Java usa IEEE-754 para su tipo de datos doble. Así que debería ser capaz de lanzarlo hacia adelante y hacia atrás para forzar la pérdida de precisión, pero los viajes redondos. Desconcertado por esto comencé a profundizar en Java y ahora estoy realmente confundido.
Tanto en C# y Java, los valores mínimo y máximo para una larga son los mismos:
long MIN_VALUE = -9223372036854775808L;
long MAX_VALUE = 9223372036854775807L;
AFAIK, estos valores están fuera de los números representables en IEEE-754 debido a los bits fijos reservados para el exponente y firme.
// this fails in browsers that have stuck with the pure ECMAScript Number format
var str = Number(-9223372036854775808).toFixed();
if ("-9223372036854775808" !== str) { throw new Error("Overflow!"); }
Esto devuelve false
para (valor = -9223372036854775808L) en Java:
boolean invalidIEEE754(long value) {
try {
return ((long)((double)value)) != value;
} catch (Exception ex) {
return true;
}
}
Esto devuelve false
para (valor = -9223372036854775808L) en Java:
boolean invalidIEEE754(long value) {
// trying to get closer to the actual representation and
// being more explicit about conversions
long bits = Double.doubleToLongBits(Long.valueOf(value).doubleValue());
long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
return (value != roundtrip);
}
Esto devuelve true
para (valor = -9223372036854775808L) pero es menos preciso:
boolean invalidIEEE754(long value) {
return (0x0L != (0xFFF0000000000000L & (value < 0L ? -value : value)));
}
¿Por qué funciona de esta manera? ¿Me falta algo como la optimización del compilador, p. ¿El compilador detecta mis conversiones y las "arregla" por mí?
Edición: Agregar caso de prueba por solicitud. Los tres de estas pruebas falla:
import static org.junit.Assert.*;
import org.junit.Test;
public class FooTests {
@Test
public void ieee754One() {
assertTrue(((long)((double)Long.MIN_VALUE)) != Long.MIN_VALUE);
}
@Test
public void ieee754Two() {
long bits = Double.doubleToLongBits(Long.valueOf(Long.MIN_VALUE).doubleValue());
long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
assertTrue(Long.MIN_VALUE != roundtrip);
}
@Test
public void ieee754Three() {
long bits = Double.doubleToRawLongBits(Long.valueOf(Long.MIN_VALUE).doubleValue());
long roundtrip = Double.valueOf(Double.longBitsToDouble(bits)).longValue();
assertTrue(Long.MIN_VALUE != roundtrip);
}
}
Ambos métodos devuelven 'false' para mí. JDK 1.6.0_21. – axtavt
¡Interesante! Ahora estoy realmente confundido. El mío se está ejecutando a través de JUnit, pero también debe estar en JDK 1.6.0_21. – mckamey
¿Puedes mostrar el caso de prueba completo ?. – axtavt