¿Se les permite a los motores JS cambiar los bits de un NaN?

12

En JavaScript, el valor de NaN se puede representar mediante una amplia gama de dobles de 64 bits internamente. Específicamente, cualquier doble con la siguiente representación bit a bit:

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

Se interpreta como un NaN. Mi pregunta es: supongamos que lanzo dos uniones de 32 bits a un Número JS usando ArrayBuffers, lo paso y luego lo vuelvo a emitir a dos uniones de 32 bits. ¿Los bits recuperados serán los mismos que los originales, o los motores JS pueden cambiar los bits de un NaN a voluntad? En otras palabras, ¿se pueden usar los números JS para almacenar 64 bits sin pérdida?

MaiaVictor
fuente
2
Idea interesante
Evert
1
Una prueba que hice. Parece que al menos Node.js cambia los bits a voluntad, causando pérdida de información.
MaiaVictor
1
Aparte: no todos los patrones de bits representan un NaN. Si todos los peros x después del primero son cero, representa un infinito.
Eric Postpischil

Respuestas:

6

ECMA-262 9 ª edición, junio de 2018, (la norma a la que se destina JavaScript para ajustarse) dice, en 6.1.6 “el tipo de número”:

... los 9007199254740990 (es decir, 2 53 -2) valores distintos de "No un número" del Estándar IEEE están representados en ECMAScript como un único valor especial de NaN ... En algunas implementaciones, el código externo puede detectar una diferencia entre varios valores No-a-Number, pero dicho comportamiento depende de la implementación; para el código ECMAScript, todos los valores de NaN son indistinguibles entre sí.

24.1.17 "NumberToRawBytes (tipo, valor, isLittleEndian)" dice:

... Si el valor es NaN, rawBytes se puede establecer en cualquier implementación elegida en formato IEEE 754-2008 binary64 codificación Not-a-Number. Una implementación siempre debe elegir la misma codificación para cada valor de NaN distinguible de implementación ...

No veo ningún otro pasaje que mencione NaN que sea esclarecedor sobre esta pregunta. Por un lado, 24.1.17 efectivamente nos dice que los bits de un NaN se deben preservar al convertir el NaN en bytes sin formato. Sin embargo, nada más parece decirnos que los bits deben preservarse en otras operaciones. Se podría deducir que esta es la intención, porque este requisito en 24.1.17 no serviría de nada si los bits pudieran ser cambiados arbitrariamente por cualquier otra operación. Pero no confiaría en las implementaciones de JavaScript para implementar esto de conformidad con esa intención.

Eric Postpischil
fuente
1

Una vez hice una pregunta para Java, sobre la dependencia del hardware de los valores de NaN, y me di cuenta de que algunas CPU convertirían silenciosamente un "NaN de señalización" en un "NaN silencioso" (configurando el bit NaN silencioso) cuando se carga un valor NaN en un registro de procesador. Entonces, al menos uno de los bits, el bit NaN silencioso, no se puede usar para almacenar datos arbitrarios.

El uso de los otros bits, siempre y cuando se establezca el bit NaN silencioso, probablemente sea seguro. Pero todavía parece haber espacio para la dependencia de implementación aquí, y por lo tanto no hay garantía.

Este tipo de problema es la razón por la cual las operaciones de lenguaje normales evitan hacer algo que dependa del valor interno de un NaN, y prefieren tratar todos los NaN como "solo NaN".

Boann
fuente
0

El estándar original IEEE-754 dejó deliberadamente los bits de un NaN hasta la implementación. Proporcionó pistas, como

Puede poner la dirección de memoria original de donde se creó el NaN.

Mientras tanto, la aritmética tiene reglas específicas sobre qué hacer con un NaN, y eso no tiene nada que ver con los bits en la parte inferior. No creo que incluso diga qué hacer al agregar dos NaN: mantener los bits de uno de ellos en lugar de crear otro conjunto de bits. Solo que el resultado debe ser un NaN.

Rick James
fuente