Je suis en train de revoir une question (How to test if numeric conversion will change value?) qui, en ce qui me concerne, a été entièrement résolue. Le problème était de détecter lorsqu'une valeur numérique particulière dépassait le type de numéro IEEE-754 de JavaScript. La question précédente utilisait C# et la réponse marquée fonctionnait parfaitement.IEEE-754 Double (virgule flottante 64 bits) vs longue (entier de 64 bits) Revisited
Maintenant, je fais exactement la même tâche mais cette fois en Java et cela ne fonctionne pas. AFAIK, Java utilise IEEE-754 pour son double type de données. Je devrais donc être capable de le lancer d'avant en arrière pour forcer la perte de précision, mais il faut faire des allers-retours. Déconcerté par cela j'ai commencé à pousser plus loin dans Java et maintenant je suis vraiment confus.
Dans C# et Java, les valeurs minimales et maximales pour longtemps sont les mêmes:
long MIN_VALUE = -9223372036854775808L;
long MAX_VALUE = 9223372036854775807L;
AFAIK, ces valeurs sont en dehors des nombres représentables dans la norme IEEE-754 en raison des bits fixes réservés à l'exposant et signe.
// 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!"); }
Cela renvoie false
pour (valeur = -9223372036854775808L) en Java:
boolean invalidIEEE754(long value) {
try {
return ((long)((double)value)) != value;
} catch (Exception ex) {
return true;
}
}
Cela renvoie false
pour (valeur = -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);
}
Ce retourne true
pour (valeur = -9223372036854775808L) mais est moins précis:
boolean invalidIEEE754(long value) {
return (0x0L != (0xFFF0000000000000L & (value < 0L ? -value : value)));
}
Pourquoi cela fonctionne-t-il de cette façon? Ai-je manqué quelque chose comme l'optimisation du compilateur, par ex. Est-ce que le compilateur détecte mes conversions et les "corrige" pour moi?
Édition: Ajout d'un cas de test sur demande. Tous les trois de ces tests échouent:
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);
}
}
Les deux méthodes retournent 'false' pour moi. JDK 1.6.0_21. – axtavt
Intéressant! Maintenant, je suis vraiment confus. Le mien fonctionne via JUnit mais devrait aussi être sur JDK 1.6.0_21. – mckamey
Pouvez-vous montrer le test complet? – axtavt