J'étais en train de lire sur les valeurs NaN en virgule flottante dans la spécification du langage Java (je suis ennuyeux). Un programme 32 bits float
a ce format de bit :
seee eeee emmm mmmm mmmm mmmm mmmm mmmm
s
est le bit de signe, e
sont les bits de l'exposant, et m
sont les bits de la mantisse. Une valeur NaN est codée comme un exposant de tous les 1 et les bits de la mantisse ne sont pas tous 0 (ce qui serait +/- l'infini). Cela signifie qu'il existe un grand nombre de valeurs NaN différentes possibles (ayant des valeurs s
y m
valeurs binaires).
Là-dessus, JLS §4.2.3 dit :
La norme IEEE 754 autorise plusieurs valeurs NaN distinctes pour chacun de ses formats à virgule flottante simple et double. Bien que chaque architecture matérielle renvoie un motif binaire particulier pour NaN lorsqu'un nouveau NaN est généré, un programmeur peut également créer des NaN avec différents motifs binaires pour coder, par exemple, des informations de diagnostic rétrospectives.
Le texte de la JLS semble impliquer que le résultat de, par exemple, 0.0/0.0
Selon que cette expression a été calculée comme une constante de compilation, le matériel dont elle dépend peut être le matériel sur lequel le programme Java a été compilé ou le matériel sur lequel le programme a été exécuté. Tout ceci semble très flasque si c'est vrai.
J'ai effectué le test suivant :
System.out.println(Integer.toHexString(Float.floatToRawIntBits(0.0f/0.0f)));
System.out.println(Integer.toHexString(Float.floatToRawIntBits(Float.NaN)));
System.out.println(Long.toHexString(Double.doubleToRawLongBits(0.0d/0.0d)));
System.out.println(Long.toHexString(Double.doubleToRawLongBits(Double.NaN)));
La sortie sur ma machine est :
7fc00000
7fc00000
7ff8000000000000
7ff8000000000000
La sortie indique que les bits de l'exposant sont à 1 comme prévu. Le bit supérieur de la mantisse est également 1, ce qui, pour les NaN, indique apparemment un "NaN silencieux" par opposition à un "NaN de signalisation" ( https://en.wikipedia.org/wiki/NaN#Floating_point ). Le bit de signe et le reste des bits de mantisse sont à 0. La sortie indique également qu'il n'y a pas de différence entre les NaN générés sur ma machine et les NaN constants des classes Float et Double.
Ma question est la suivante : cette sortie est-elle garantie en Java, indépendamment du CPU du compilateur ou de la VM, ou tout cela est-il vraiment imprévisible ? Le JLS est mystérieux à ce sujet.
Si cette sortie est garantie pour 0.0/0.0
Dans le cas d'un NaN, existe-t-il des moyens arithmétiques de produire des NaN avec d'autres modèles de bits (dépendant éventuellement du matériel) ? (Je sais que je pourrais utiliser intBitsToFloat
/ longBitsToDouble
pour coder d'autres NaNs délibérément, mais j'aimerais savoir si d'autres valeurs peuvent se produire à partir de l'arithmétique normale).
Une question complémentaire : J'ai remarqué que Float.NaN y Double.NaN spécifient leur configuration binaire exacte, mais dans la source ( Flotteur , Double ) ils sont générés par 0.0/0.0. Si ce résultat dépend réellement du matériel du compilateur, la spécification est erronée, n'est-ce pas, et ne peut pas réellement faire cette garantie ?