Pergunta

Alguns dos meus dados são inteiros de 64 bits. Gostaria de enviá-los a um programa de JavaScript em execução em uma página.

No entanto, tanto quanto eu posso dizer, inteiros na maioria das implementações de JavaScript são de 32 bits quantidades assinados.

As minhas duas opções parecem ser:

  1. Enviar os valores como strings
  2. Enviar os valores como números de ponto flutuante de 64-bits

Opção (1) não é perfeito, mas a opção (2) parece muito menos perfeito (perda de dados).

Como você tem tratado esta situação?

Foi útil?

Solução

Esta parece ser menos um problema com JSON e mais um problema com o próprio Javascript. O que você está planejando fazer com esses números? Se é apenas uma magia token que você precisa para passar de volta para o site mais tarde, por todos os meios simplesmente usar uma string contendo o valor. Se você realmente tem que fazer contas sobre o valor, você poderia escrever suas próprias rotinas Javascript para 64-bit aritmética.

Uma maneira que você poderia representar valores no Javascript (e, portanto, JSON) seria, dividindo os números em dois valores de 32 bits, por exemplo.

  [ 12345678, 12345678 ]

Para dividir um valor de 64 bits em dois valores de 32 bits, fazer algo como isto:

  output_values[0] = (input_value >> 32) & 0xffffffff;
  output_values[1] = input_value & 0xffffffff;

Em seguida, a recombinar-se dois valores de 32 bits para um valor de 64 bits:

  input_value = ((int64_t) output_values[0]) << 32) | output_values[1];

Outras dicas

Há de fato uma limitação a nível JavaScript / ECMAScript de precisão para 53 bits para inteiros (eles são armazenados no mantissa de um 8 bytes tampão "como duplo" de memória). Assim transmitir grandes números como JSON não serão desserializados como esperado pelo cliente JavaScript, o que truncar-los a sua resolução de 53-bit.

> parseInt("10765432100123456789")
10765432100123458000

Veja a Number.MAX_SAFE_INTEGER constante e Number.isSafeInteger() função:

A constante MAX_SAFE_INTEGER tem um valor de 9007199254740991. o raciocínio por trás desse número é que o JavaScript utiliza precisão dupla formatar números de ponto flutuante, tal como especificado na norma IEEE 754 e só pode representam de forma segura números entre -(2^53 - 1) e 2^53 - 1.

Seguro neste contexto refere-se à capacidade de representar inteiros exatamente e corretamente compará-los. Por exemplo, vontade Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 avaliar a true, que é matematicamente incorreta. Vejo Number.isSafeInteger() para mais informações.

Devido à resolução de carros alegóricos em JavaScript, usando "números de ponto flutuante de 64 bits", como você propôs sofreria a mesma restrição.

IMHO a melhor opção é transmitir valores como texto. Seria conteúdo JSON ainda perfeitamente legível, e seria fácil fazer um trabalho a nível JavaScript.

A "string pura" representação é o que OData especifica, por seus tipos Edm.Int64 ou Edm.Decimal .

O que o Twitter API faz neste caso, é adicionar um campo específico ".._str": no JSON, como tal:

{
   "id": 10765432100123456789,           // for JSON compliant clients
   "id_str": "10765432100123456789",     // for JavaScript
    ...
}

Eu gosto desta opção muito, uma vez que seria ainda compatível com os clientes capazes int64. Na prática, tal conteúdo duplicado no JSON não vai doer muito, se é esvaziado / gzipped a nível HTTP.

Uma vez transmitida como string, você pode usar bibliotecas como strint - uma biblioteca JavaScript para inteiros codificados em cordas para lidar com tais valores.

tipo Número de Javascript (64 bit IEEE 754) tem apenas cerca de 53 bits de precisão.

Mas, se você não precisa fazer qualquer adição ou multiplicação, então você poderia manter valor de 64 bits como cordas de 4 caracteres como JavaScript usa UTF-16.

Por exemplo, 1 poderia ser codificado como "\ u0000 \ u0000 \ u0000 \ u0001". Isto tem a vantagem de comparação de valor (==,>, <) trabalha em cordas como esperado. Também parece simples para operações de bit de escrita:

function and64(a,b) {
    var r = "";
    for (var i = 0; i < 4; i++)
        r += String.fromCharCode(a.charCodeAt(i) & b.charCodeAt(i));
    return r;
}

A representação número JS é um IEEE duplo padrão, então você não pode representar um número inteiro de 64 bit. IIRC você começa talvez 48 bits de precisão int real em um duplo, mas todos bitops JS reduzir a precisão de 32 bits (que é o que a especificação exige. yay!) por isso, se você realmente precisa de um int de 64 bits em js que você precisa para implementar seu próprio 64 bit biblioteca lógica int.

JSON em si não se preocupa com limites de implementação. o problema é que JS não pode lidar com os seus dados, não o protocolo. Em outras palavras, o código do cliente JS tem que usar qualquer uma dessas opções não-perfeitas.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top