一部のデータは 64 ビット整数です。これらをページ上で実行されている JavaScript プログラムに送信したいと考えています。
ただし、私が知る限り、ほとんどの JavaScript 実装の整数は 32 ビット符号付きの量です。
私の2つのオプションは次のようです:
- 値を文字列として送信
- 値を 64 ビット浮動小数点数として送信する
オプション (1) は完全ではありませんが、オプション (2) は完全ではないようです (データの損失)。
この状況にどのように対処しましたか?
一部のデータは 64 ビット整数です。これらをページ上で実行されている JavaScript プログラムに送信したいと考えています。
ただし、私が知る限り、ほとんどの JavaScript 実装の整数は 32 ビット符号付きの量です。
私の2つのオプションは次のようです:
オプション (1) は完全ではありませんが、オプション (2) は完全ではないようです (データの損失)。
この状況にどのように対処しましたか?
これは、JSON の問題ではなく、Javascript 自体の問題のようです。この数字で何をするつもりですか?後で Web サイトに戻す必要がある単なるマジック トークンである場合は、必ず値を含む文字列を使用してください。実際に値に対して算術演算を行う必要がある場合は、64 ビット演算用の独自の Javascript ルーチンを作成できる可能性があります。
Javascript (したがって JSON) で値を表す 1 つの方法は、数値を 2 つの 32 ビット値に分割することです。
[ 12345678, 12345678 ]
64 ビット値を 2 つの 32 ビット値に分割するには、次のようにします。
output_values[0] = (input_value >> 32) & 0xffffffff;
output_values[1] = input_value & 0xffffffff;
次に、2 つの 32 ビット値を 64 ビット値に再結合します。
input_value = ((int64_t) output_values[0]) << 32) | output_values[1];
実際、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()
してください。
あなたが提案したように「64ビット浮動小数点数」を使用すると、JavaScriptでの浮動小数点数の解決により、まったく同じ制限が課せられます。
私見の最良の選択肢は、そのような値をテキストとして送信することです。それでも完全に読み取り可能な JSON コンテンツであり、JavaScript レベルで簡単に操作できます。
「純粋な文字列」表現は、そのor型に対して OData が指定するEdm.Int64
Edm.Decimal
ものです。
この場合に Twitter API が行うことは".._str":
、JSON に特定のフィールドを追加することです。
{
"id": 10765432100123456789, // for JSON compliant clients
"id_str": "10765432100123456789", // for JavaScript
...
}
このオプションは、int64 対応のクライアントと互換性があるため、非常に気に入っています。実際には、JSON 内のこのような重複したコンテンツは、HTTP レベルで圧縮/gzip されている場合、それほど害はありません。
文字列として送信されたら、strint などのライブラリを使用できます。これは、文字列でエンコードされた整数の JavaScript ライブラリで、そのような値を処理します。
更新: JavaScript エンジンの新しいバージョンには、53 ビット以上を処理できるBigIntオブジェクト クラスが含まれています。実際、任意の大きな整数に使用できるため、64 ビット整数値に適しています。しかし、JSON としてシリアル化する場合、BigInt 値は JSON 文字列としてシリアル化されます。奇妙なことに、互換性のために推測します。
Javascript の Number 型 (64 ビット IEEE 754) は、約 53 ビットの精度しかありません。
ただし、加算や乗算を行う必要がない場合は、JavaScript が UTF-16 を使用するため、64 ビット値を 4 文字の文字列として保持できます。
たとえば、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 double であるため、64 ビット整数を表すことはできません。iirc では double でおそらく 48 ビットの実際の int 精度が得られますが、すべての JS bitops は 32 ビットの精度に削減されます (これが仕様で要求されていることです。イェイ!)。したがって、js で 64 ビットの int が本当に必要な場合は、独自の64 ビット int ロジック ライブラリ。
JSON 自体は、実装の制限を気にしません。問題は、プロトコルではなく、JS がデータを処理できないことです。つまり、JS クライアント コードでは、これらの不完全なオプションのいずれかを使用する必要があります。