36

我的一些数据是 64 位整数。我想将这些发送到在页面上运行的 JavaScript 程序。

然而,据我所知,大多数 JavaScript 实现中的整数都是 32 位有符号数。

我的两个选择似乎是:

  1. 将值作为字符串发送
  2. 将值作为 64 位浮点数发送

选项 (1) 并不完美,但选项 (2) 似乎远没有那么完美(数据丢失)。

你是如何处理这种情况的?

4

6 回答 6

26

这似乎不是 JSON 的问题,而是 Javascript 本身的问题。你打算用这些数字做什么?如果它只是您需要稍后传递回网站的魔术令牌,请务必使用包含该值的字符串。如果您实际上必须对值进行算术运算,您可以编写自己的 Javascript 例程来进行 64 位算术运算。

您可以在 Javascript(以及 JSON)中表示值的一种方法是将数字拆分为两个 32 位值,例如。

  [ 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];
于 2008-10-16T19:20:29.620 回答
23

事实上,JavaScript/ECMAScript 的整数精度限制为 53 位(它们存储在“类似双精度”的 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.Int64Edm.Decimal类型

在这种情况下,Twitter API 所做的是".._str":在 JSON 中添加一个特定字段,如下所示:

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

我非常喜欢这个选项,因为它仍然与支持 int64 的客户端兼容。在实践中,如果在 HTTP 级别对 JSON 中的此类重复内容进行压缩/压缩,则不会造成太大影响。

一旦以字符串形式传输,您就可以使用strint 之类的库——一个用于字符串编码整数的 JavaScript 库来处理此类值。

更新:较新版本的 JavaScript 引擎包括一个BigInt对象类,它能够处理超过 53 位。事实上,它可以用于任意大的整数,因此非常适合 64 位整数值。但是当序列化为 JSON 时,BigInt 值将被序列化为 JSON 字符串——这很奇怪,但我猜是出于兼容性目的。

于 2016-01-25T09:43:58.140 回答
7

Javascript 的数字类型(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;
}
于 2009-05-13T16:08:16.243 回答
2

JS 数字表示是标准的 ieee double,所以不能表示 64 位整数。iirc 你可能会得到 48 位的实际 int 精度,但所有 JS bitops 都会降低到 32 位精度(这就是规范所要求的。耶!)所以如果你真的需要 js 中的 64 位 int,你需要实现你自己的64 位 int 逻辑库。

于 2008-10-16T21:17:27.683 回答
0

JSON 本身并不关心实现限制。您的问题是 JS 无法处理您的数据,而不是协议。换句话说,您的 JS 客户端代码必须使用这些不完美的选项中的任何一个。

于 2008-10-16T19:15:41.877 回答
0

这件事发生在我身上。当通过 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));

我得到的行为是指针数学变得非常糟糕的那种东西。鬼从我的工作站飞出,在我的睡眠中造成严重破坏。现在我切换到弦乐,它们都被驱除了。

于 2020-07-07T09:18:50.657 回答