Les moteurs JS sont-ils autorisés à modifier les bits d'un NaN?

12

En JavaScript, la valeur NaN peut être représentée par une large gamme de doubles 64 bits en interne. Plus précisément, tout double avec la représentation au niveau du bit suivante:

x111 1111 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx xxxx

Est interprété comme un NaN. Ma question est la suivante: supposons que je jette deux uints 32 bits vers un numéro JS à l'aide d'ArrayBuffers, je le passe, puis je le restitue en deux uints 32 bits. Les bits récupérés seront-ils les mêmes que ceux d'origine, ou les moteurs JS sont-ils autorisés à modifier les bits d'un NaN à volonté? En d'autres termes, les numéros JS peuvent-ils être utilisés pour stocker avec perte 64 bits?

MaiaVictor
la source
2
Idée intéressante
Evert
1
Un test que j'ai fait. Il semble qu'au moins Node.js modifie les bits à volonté, entraînant une perte d'informations.
MaiaVictor
1
En plus: tous ces motifs binaires ne représentent pas un NaN. Si tous les x mais après le premier sont nuls, cela représente un infini.
Eric Postpischil

Réponses:

6

ECMA-262 9 e édition, juin 2018 (la norme à laquelle JavaScript est censé se conformer) dit, en 6.1.6 «Le type de numéro»:

… Les valeurs 9007199254740990 (c'est-à-dire 2 53 -2) distinctes «Pas un numéro» de la norme IEEE sont représentées dans ECMAScript comme une seule valeur NaN spéciale.… Dans certaines implémentations, le code externe peut détecter une différence entre diverses valeurs Not-a-Number, mais un tel comportement dépend de l'implémentation; au code ECMAScript, toutes les valeurs de NaN sont indiscernables les unes des autres.

24.1.17 «NumberToRawBytes (type, valeur, isLittleEndian)» dit:

… Si la valeur est NaN, rawBytes peut être défini sur n'importe quelle implémentation choisie, codage IEEE 754-2008 binaire64 au format Not-a-Number. Une implémentation doit toujours choisir le même codage pour chaque valeur NaN distincte de l'implémentation.…

Je ne vois aucun autre passage mentionnant NaN qui soit éclairant sur cette question. D'une part, 24.1.17 nous dit effectivement que les bits d'un NaN doivent être préservés lors de la conversion du NaN en octets bruts. Cependant, rien d'autre ne semble nous dire que les bits doivent être conservés dans d'autres opérations. On pourrait en déduire que c'est l'intention, car cette exigence du 24.1.17 ne servirait à rien si les bits pouvaient être modifiés arbitrairement par toute autre opération. Mais je ne compterais pas sur les implémentations JavaScript pour avoir implémenté cela conformément à cette intention.

Eric Postpischil
la source
1

Une fois, j'ai posé une question à Java, sur la dépendance matérielle des valeurs NaN, et il a été remarqué que certains processeurs convertissent silencieusement un "NaN de signalisation" en un "NaN silencieux" (définition du bit NaN silencieux) lorsqu'une valeur NaN est chargée dans un registre de processeur. Donc, au moins un des bits, le bit NaN silencieux, vous ne pouvez pas utiliser pour stocker des données arbitraires.

L'utilisation des autres bits, tant que le bit NaN silencieux est défini, est probablement sûre. Mais il semble toujours y avoir de la place pour la mise en œuvre dépendante, et donc aucune garantie.

Ce type de problème explique pourquoi les opérations de langage normales évitent de faire quoi que ce soit qui dépend de la valeur interne d'un NaN, et préfèrent traiter tous les NaN comme "juste NaN".

Boann
la source
0

La norme IEEE-754 d'origine a délibérément laissé les bits d'un NaN à la mise en œuvre. Il a fourni des conseils, tels que

Vous pouvez mettre l'adresse mémoire d'origine de l'endroit où le NaN a été créé.

Pendant ce temps, l'arithmétique a des règles spécifiques sur ce qu'il faut faire avec un NaN, et cela n'a rien à voir avec les bits en bas. Je ne pense pas qu'il indique même quoi faire lors de l'ajout de deux NaN - conserver les bits de l'un d'eux par rapport à constituer un autre ensemble de bits. Juste que le résultat doit toujours être un NaN.

Rick James
la source