Разрешено ли двигателям JS менять биты NaN?

12

В JavaScript значение NaN может быть внутренне представлено широким диапазоном 64-битных двойных чисел. В частности, любой дубль со следующим побитовым представлением:

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

Это интерпретируется как NaN. Мой вопрос: предположим, что я приведу две 32-битные уинты к JS-номеру с помощью ArrayBuffers, передам его, а затем приведу обратно к двум 32-битным уинтам. Будут ли восстановленные биты такими же, как исходные, или JS-движкам разрешено изменять биты NaN по желанию? Другими словами, могут ли номера JS использоваться для хранения 64-битных данных без потерь?

MaiaVictor
источник
2
Интересная идея
Evert
1
Тест я сделал. Похоже, что по крайней мере Node.js изменяет биты по желанию, вызывая потерю информации.
MaiaVictor
1
В сторону: не каждый такой битовый шаблон представляет собой NaN. Если все x битов после первого равны нулю, это представляет бесконечность.
Эрик Постпишил

Ответы:

6

ECMA-262, 9- е издание, июнь 2018 г. (стандарт, которому должен соответствовать JavaScript) в 6.1.6 «Тип числа» гласит:

… 9007199254740990 (то есть 2 53 -2) различных значений «Not-a-Number» стандарта IEEE представлены в ECMAScript как отдельное специальное значение NaN.… В некоторых реализациях внешний код может обнаруживать разницу между различными значениями Not-a-Number, но такое поведение зависит от реализации; для кода ECMAScript все значения NaN неотличимы друг от друга.

24.1.17 «NumberToRawBytes (тип, значение, isLittleEndian)» говорит:

… Если значение равно NaN, rawBytes может быть установлен для любой выбранной реализации кодировки Not-a-Number формата IEEE 754-2008 binary64. Реализация всегда должна выбирать одну и ту же кодировку для каждого различимого значения реализации NaN…

Я не вижу других отрывков, в которых упоминается NaN, освещающих этот вопрос. С одной стороны, 24.1.17 фактически говорит нам, что биты NaN должны быть сохранены при преобразовании NaN в необработанные байты. Однако больше ничего не говорит нам, что биты должны быть сохранены в других операциях. Можно сделать вывод, что это намерение, потому что это требование в 24.1.17 не будет иметь смысла, если биты могут быть произвольно изменены любой другой операцией. Но я бы не стал полагаться на реализации JavaScript, чтобы реализовать это в соответствии с этим намерением.

Эрик Постпищил
источник
1

Однажды я задал вопрос для Java об аппаратной зависимости значений NaN, и было замечено, что некоторые процессоры будут молча преобразовывать «сигнальный NaN» в «тихий NaN» (устанавливая тихий бит NaN) при загрузке значения NaN в регистр процессора. Поэтому, по крайней мере, один из битов, тихий бит NaN, вы не можете использовать для хранения произвольных данных.

Использование других битов, пока установлен тихий бит NaN, вероятно, безопасно. Но все же, похоже, здесь есть место для зависимости от реализации, и, следовательно, нет никакой гарантии.

Проблема такого рода заключается в том, что обычные языковые операции избегают делать что-либо, зависящее от внутреннего значения NaN, и предпочитают рассматривать все NaN как «просто NaN».

Boann
источник
0

Первоначальный стандарт IEEE-754 намеренно оставил биты NaN вплоть до реализации. Он предоставил подсказки, такие как

Вы можете поместить оригинальный адрес памяти, где был создан NaN.

Между тем, арифметика имеет определенные правила о том, что делать с NaN, и это не имеет ничего общего с битами внизу. Я не думаю, что это даже говорит о том, что делать при добавлении двух NaN - сохранить биты одного из них вместо создания другого набора битов. Просто результат должен быть NaN.

Рик Джеймс
источник