Os mecanismos JS podem alterar os bits de um NaN?

12

Em JavaScript, o valor NaN pode ser representado por uma ampla variedade de dobras de 64 bits internamente. Especificamente, qualquer duplo com a seguinte representação bit a bit:

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

É interpretado como um NaN. Minha pergunta é: suponha que eu conjure duas uints de 32 bits em um número JS usando ArrayBuffers, passe-as e depois as converta novamente em duas uints de 32 bits. Os bits recuperados serão iguais aos originais, ou os mecanismos JS podem alterar os bits de um NaN à vontade? Em outras palavras, os números JS podem ser usados ​​para armazenar perdas de 64 bits?

MaiaVictor
fonte
2
Idéia interessante
Evert 7/19
11
Um teste que eu fiz. Parece que pelo menos o Node.js altera os bits à vontade, causando perda de informações.
MaiaVictor 07/11/19
11
Além: Nem todo padrão de bits representa um NaN. Se todos os x buts após o primeiro forem zero, isso representa um infinito.
Eric Postpischil 8/11/19

Respostas:

6

ECMA-262 9 ª Edição, Junho de 2018, (o padrão ao qual se destina o JavaScript para conformar) diz, em 6.1.6 “o tipo de número”:

… Os valores 9007199254740990 (isto é, 2 53 -2) distintos “Não é um número” do Padrão IEEE são representados no ECMAScript como um único valor NaN especial.… Em algumas implementações, o código externo pode detectar uma diferença entre vários valores que não são um número, mas esse comportamento depende da implementação; para o código ECMAScript, todos os valores de NaN são indistinguíveis um do outro.

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

… Se o valor for NaN, rawBytes pode ser configurado para qualquer implementação escolhida, codificação IEEE 754-2008 no formato binary64 Não-numérico. Uma implementação deve sempre escolher a mesma codificação para cada valor distinguível de NaN.…

Não vejo nenhuma outra passagem que mencione NaN que esteja esclarecendo essa questão. Por um lado, 24.1.17 nos diz efetivamente que os bits de um NaN devem ser preservados ao converter o NaN em bytes brutos. No entanto, nada mais parece nos dizer que os bits devem ser preservados em outras operações. Pode-se deduzir que essa é a intenção, porque esse requisito em 24.1.17 não serviria para nada se os bits pudessem ser arbitrariamente alterados por qualquer outra operação. Mas eu não confiaria nas implementações de JavaScript para implementá-las em conformidade com essa intenção.

Eric Postpischil
fonte
1

Certa vez, fiz uma pergunta para Java sobre a dependência de hardware dos valores de NaN, e percebemos que algumas CPUs convertem silenciosamente um "NaN de sinalização" em um "NaN silencioso" (configurando o bit silencioso de NaN) quando um valor NaN é carregado em um registro do processador. Portanto, pelo menos um dos bits, o silencioso NaN, você não pode usar para armazenar dados arbitrários.

Usar os outros bits, desde que o bit NaN silencioso esteja definido, provavelmente é seguro. Mas ainda parece haver espaço para dependência de implementação aqui e, portanto, nenhuma garantia.

Esse tipo de problema é o motivo pelo qual as operações normais de linguagem evitam fazer qualquer coisa que dependa do valor interno de um NaN e preferem tratar todos os NaNs como "apenas NaN".

Boann
fonte
0

O padrão IEEE-754 original deixou deliberadamente os bits de um NaN até a implementação. Ele forneceu dicas, como

Você pode colocar o endereço de memória original de onde o NaN foi criado.

Enquanto isso, a aritmética tem regras específicas sobre o que fazer com um NaN, e isso não tem nada a ver com os bits no fundo. Eu acho que nem diz o que fazer ao adicionar dois NaNs - mantenha os bits de um deles em vez de criar outro conjunto de bits. Só que o resultado ainda deve ser um NaN.

Rick James
fonte