我的一些数据是64位整数,我想将它们发送给运行在页面上的JavaScript程序。
然而,据我所知,大多数JavaScript实现中的整数是32位有符号量。
我的两个选择似乎是:
- 将值作为字符串发送
- 将值作为64位浮点数发送
选项(1)并非完美,但选项(2)似乎不太完美(会有数据丢失)。
您如何处理这种情况?
我的一些数据是64位整数,我想将它们发送给运行在页面上的JavaScript程序。
然而,据我所知,大多数JavaScript实现中的整数是32位有符号量。
我的两个选择似乎是:
选项(1)并非完美,但选项(2)似乎不太完美(会有数据丢失)。
您如何处理这种情况?
实际上,在JavaScript/ECMAScript级别上,整数的精度限制为53位(它们存储在“类似double”的8字节内存缓冲区的尾数中)。因此,将大数字作为JSON传输将无法按预期由JavaScript客户端反序列化,这会将它们截断到其53位分辨率。
> parseInt("10765432100123456789")
10765432100123458000
请查看 Number.MAX_SAFE_INTEGER
常量 和 Number.isSafeInteger()
函数:
MAX_SAFE_INTEGER
常量的值为9007199254740991
。这个数字的背后原理是,JavaScript 使用 IEEE 754 规定的双精度浮点格式表示数字,只能安全地表示介于-(2^53 - 1)
和2^53 - 1
之间的数字。在此上下文中,“安全”指的是能够准确地表示整数并正确比较它们。例如,
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2
的结果将会是true
,然而从数学角度来说是不正确的。有关更多信息,请参见Number.isSafeInteger()
。
由于 JavaScript 中浮点数的分辨率限制,使用您提出的“64位浮点数”会遭受相同的限制。
我认为最好的选择是将这些值作为文本传输。这仍将是完全可读的 JSON 内容,并且很容易在 JavaScript 层面上处理。
OData 为其 Edm.Int64
或 Edm.Decimal
类型指定了“纯字符串”表示方法。
在此情况下,Twitter API 所做的是在 JSON 中添加一个特定的 ".._str":
字段,如下所示:
{
"id": 10765432100123456789, // for JSON compliant clients
"id_str": "10765432100123456789", // for JavaScript
...
}
我非常喜欢这个选项,因为它仍然与支持int64的客户端兼容。 实际上,在JSON中这样重复的内容不会对性能造成太大影响,如果在HTTP级别进行压缩,则效果更佳。
一旦以字符串形式传输,您可以使用类似 strint - 用于处理字符串编码整数的 JavaScript 库 的库来处理这些值。
更新:JavaScript 引擎的新版本包括一个BigInt对象类,它能够处理超过53位的整数。实际上,它可用于任意大的整数,因此非常适合64位整数值。但是,在将其序列化为JSON时,BigInt 值将作为 JSON 字符串序列化 - 这可能有些奇怪,但我想是出于兼容性考虑。
[ 12345678, 12345678 ]
要将一个64位的值分成两个32位的值,可以像这样处理:
output_values[0] = (input_value >> 32) & 0xffffffff;
output_values[1] = input_value & 0xffffffff;
将两个32位的值重新组合成一个64位的值:
input_value = ((int64_t) output_values[0]) << 32) | output_values[1];
Javascript的Number类型(64位IEEE 754)只有大约53位的精度。
但是,如果您不需要进行任何加法或乘法运算,则可以将64位值保留为4个字符的字符串,因为JavaScript使用UTF-16。
例如,1可以编码为"\u0000\u0000\u0000\u0001"。这样做的好处是字符串的值比较(==、>、<)按预期工作。同时,似乎很容易编写位运算:
function and64(a,b) {
var r = "";
for (var i = 0; i < 4; i++)
r += String.fromCharCode(a.charCodeAt(i) & b.charCodeAt(i));
return r;
}
JS数字表示是标准的IEEE双精度浮点数,因此无法表示64位整数。如果我没记错的话,你可以在双精度浮点数中获得大约48位实际整数精度,但所有JS位操作都会减少到32位精度(这是规范要求的。耶!)所以,如果你真的需要在JS中使用64位整数,你将需要实现自己的64位整数逻辑库。
JSON本身并不关心实现限制。 你的问题是JS无法处理你的数据,而不是协议的问题。 换句话说,你的JS客户端代码必须使用其中的任一非完美选项。
我遇到了这个问题。当通过json发送大整数到JSON.parse时,一切都变得混乱不堪。我花了几天时间来尝试调试。当我将值作为字符串传输时,问题立即解决。
使用
而不是
{ "the_sequence_number": "20200707105904535" }
{ "the_sequence_number": 20200707105904535 }
更糟糕的是,似乎每个实现JSON.parse的地方都是Firefox、Chrome和Opera之间共享的库,因为它们的行为完全相同。Opera的错误消息中有Chrome的URL引用,几乎像是WebKit被浏览器共享。
console.log('event_listen[' + global_weird_counter + ']: to be sure, server responded with [' + aresponsetxt + ']');
var response = JSON.parse(aresponsetxt);
console.log('event_listen[' + global_weird_counter + ']: after json parse: ' + JSON.stringify(response));
我遇到的问题是指针运算出了大问题,导致我的工作站上出现了各种幽灵,在我睡觉时制造混乱。现在我已经改用字符串,所有的幽灵都被驱逐了。