Dürfen JS-Engines die Bits eines NaN ändern?

12

In JavaScript kann der NaN-Wert intern durch einen weiten Bereich von 64-Bit-Doubles dargestellt werden. Insbesondere jedes Double mit der folgenden bitweisen Darstellung:

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

Wird als NaN interpretiert. Meine Frage lautet: Angenommen, ich wandle zwei 32-Bit-Uint mit ArrayBuffers in eine JS-Nummer um, gebe sie weiter und wandle sie dann wieder in zwei 32-Bit-Uint um. Sind die wiederhergestellten Bits dieselben wie das Original oder dürfen JS-Engines die Bits eines NaN nach Belieben ändern? Mit anderen Worten, können JS-Nummern verwendet werden, um verlustbehaftete 64-Bit-Daten zu speichern?

MaiaVictor
quelle
2
Interessante Idee
Evert
1
Ein Test, den ich gemacht habe. Es scheint, als würde mindestens Node.js die Bits nach Belieben ändern, was zu Informationsverlust führt.
MaiaVictor
1
Nebenbei: Nicht jedes dieser Bitmuster repräsentiert ein NaN. Wenn alle x aber nach dem ersten Null sind, repräsentiert dies eine Unendlichkeit.
Eric Postpischil

Antworten:

6

ECMA-262 9 - ten Auflage, Juni 2018 (der Standard , an den JavaScript sollte konform) sagt, in 6.1.6 „The Number Type“:

… Die 9007199254740990 (dh 2 53 -2) unterschiedlichen „Not-a-Number“ -Werte des IEEE-Standards werden in ECMAScript als ein einziger spezieller NaN-Wert dargestellt.… In einigen Implementierungen kann externer Code möglicherweise einen Unterschied erkennen zwischen verschiedenen Not-a-Number-Werten, aber ein solches Verhalten ist implementierungsabhängig; Nach ECMAScript-Code sind alle NaN-Werte nicht voneinander zu unterscheiden.

24.1.17 "NumberToRawBytes (Typ, Wert, isLittleEndian)" sagt:

… Wenn der Wert NaN ist, können rawBytes auf eine beliebige Implementierung gesetzt werden, die für das IEEE 754-2008-Binär64-Format Not-a-Number-Codierung ausgewählt wurde. Eine Implementierung muss immer dieselbe Codierung für jeden unterscheidbaren NaN-Wert der Implementierung auswählen.…

Ich sehe keine anderen Passagen, in denen NaN erwähnt wird und die diese Frage beleuchten. Einerseits sagt uns 24.1.17 effektiv, dass die Bits eines NaN erhalten bleiben müssen, wenn das NaN in Rohbytes konvertiert wird. Nichts anderes scheint uns jedoch zu sagen, dass die Bits in anderen Operationen erhalten bleiben müssen. Man könnte daraus schließen, dass dies die Absicht ist, da diese Anforderung in 24.1.17 keinen Zweck erfüllen würde, wenn die Bits durch eine andere Operation willkürlich geändert werden könnten. Ich würde mich jedoch nicht auf JavaScript-Implementierungen verlassen, um dies in Übereinstimmung mit dieser Absicht zu implementieren.

Eric Postpischil
quelle
1

Ich habe Java einmal eine Frage zur Hardwareabhängigkeit von NaN-Werten gestellt, und es wurde festgestellt, dass einige CPUs beim Laden eines NaN-Werts ein "signalisierendes NaN" stillschweigend in ein "leises NaN" (Setzen des leisen NaN-Bits) umwandeln in ein Prozessorregister. Mindestens eines der Bits, das leise NaN-Bit, kann also nicht zum Speichern beliebiger Daten verwendet werden.

Die Verwendung der anderen Bits ist wahrscheinlich sicher , solange das leise NaN-Bit gesetzt ist . Dennoch scheint hier Raum für Implementierungsabhängigkeit und damit keine Garantie zu bestehen.

Diese Art von Problem ist der Grund, warum normale Sprachoperationen alles vermeiden, was vom internen Wert eines NaN abhängt, und es vorziehen, alle NaNs als "nur NaN" zu behandeln.

Boann
quelle
0

Der ursprüngliche IEEE-754-Standard überließ die Bits eines NaN absichtlich der Implementierung. Es gab Hinweise wie

Sie können die ursprüngliche Speicheradresse angeben, an der das NaN erstellt wurde.

In der Zwischenzeit hat die Arithmetik spezifische Regeln, was mit einem NaN zu tun ist, und das hat nichts mit den Bits im unteren Bereich zu tun. Ich glaube nicht, dass es sagt, was zu tun ist, wenn zwei NaNs hinzugefügt werden - halten Sie die Bits von einem davon fern, anstatt einen anderen Satz von Bits zu bilden. Nur dass das Ergebnis noch ein NaN sein muss.

Rick James
quelle