Pregunta

Algunos de mis datos son enteros de 64 bits.Me gustaría enviarlos a un programa JavaScript que se ejecuta en una página.

Sin embargo, hasta donde puedo decir, los números enteros en la mayoría de las implementaciones de JavaScript son cantidades con signo de 32 bits.

Mis dos opciones parecen ser:

  1. Enviar los valores como cadenas.
  2. Envíe los valores como números de coma flotante de 64 bits.

La opción (1) no es perfecta, pero la opción (2) parece mucho menos perfecta (pérdida de datos).

¿Cómo has manejado esta situación?

¿Fue útil?

Solución

Esto parece ser menos un problema con JSON y más un problema con Javascript en sí. ¿Qué planeas hacer con estos números? Si es solo un token mágico que necesita pasar al sitio web más adelante, simplemente use una cadena que contenga el valor. Si realmente tiene que hacer aritmética en el valor, posiblemente podría escribir sus propias rutinas Javascript para aritmética de 64 bits.

Una forma de representar valores en Javascript (y, por lo tanto, JSON) sería dividiendo los números en dos valores de 32 bits, por ejemplo.

  [ 12345678, 12345678 ]

Para dividir un valor de 64 bits en dos valores de 32 bits, haga algo como esto:

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

Luego, para recombinar dos valores de 32 bits a un valor de 64 bits:

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

Otros consejos

De hecho, existe una limitación en el nivel de precisión de JavaScript/ECMAScript a 53 bits para números enteros (se almacenan en la mantisa de un búfer de memoria de 8 bytes "doble").Por lo tanto, la transmisión de números grandes como JSON no se deserializará como esperaba el cliente JavaScript, lo que los truncaría a su resolución de 53 bits.

> parseInt("10765432100123456789")
10765432100123458000

Ver el Number.MAX_SAFE_INTEGER constante y Number.isSafeInteger() función:

El MAX_SAFE_INTEGER constante tiene un valor de 9007199254740991.El razonamiento detrás de ese número es que JavaScript utiliza números de formato de punto flotante de doble precisión como se especifica en IEEE 754 y solo puede representar los números de manera segura entre -(2^53 - 1) y 2^53 - 1.

Seguro en este contexto se refiere a la capacidad de representar enteros exactamente y compararlos correctamente.Por ejemplo, Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2 evaluará a true, lo cual es matemáticamente incorrecto.Ver Number.isSafeInteger() para más información.

Debido a la resolución de los flotantes en JavaScript, el uso de "números de punto flotante de 64 bits" como usted propuso sufriría la misma restricción.

En mi humilde opinión, la mejor opción es transmitir valores como texto.Seguiría siendo contenido JSON perfectamente legible y sería fácil trabajar con él a nivel de JavaScript.

Una representación de "cadena pura" es lo que OData especifica, por su Edm.Int64 o Edm.Decimal tipos.

Lo que hace la API de Twitter en este caso es agregar un ".._str": campo en el JSON, como tal:

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

Me gusta mucho esta opción, ya que seguiría siendo compatible con clientes compatibles con int64.En la práctica, dicho contenido duplicado en JSON no hará mucho daño si se desinfla/comprime con gzip a nivel HTTP.

Una vez transmitido como cadena, puede utilizar bibliotecas como sstring: una biblioteca de JavaScript para enteros codificados en cadenas para manejar tales valores.

El tipo de número de Javascript (64 bits IEEE 754) solo tiene unos 53 bits de precisión.

Pero, si no necesita hacer ninguna adición o multiplicación, entonces podría mantener el valor de 64 bits como cadenas de 4 caracteres ya que JavaScript usa UTF-16.

Por ejemplo, 1 podría codificarse como " \ u0000 \ u0000 \ u0000 \ u0001 " ;. Esto tiene la ventaja de que la comparación de valores (==, & Gt ;, & Lt;) funciona en cadenas como se esperaba. También parece sencillo escribir operaciones de bits:

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

La representación del número JS es un ieee double estándar, por lo que no puede representar un número entero de 64 bits. Iirc obtienes tal vez 48 bits de precisión int real en un doble, pero todos los bitops JS se reducen a una precisión de 32 bits (eso es lo que requiere la especificación. Biblioteca lógica de 64 bits int.

JSON en sí mismo no se preocupa por los límites de implementación. Su problema es que JS no puede manejar sus datos, no el protocolo. En otras palabras, su código de cliente JS tiene que usar cualquiera de esas opciones no perfectas.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top