Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Каков общепринятый способ отправки 64-битных значений через JSON?

Автор вопроса: Frank KruegerОтветов: 6

Некоторые из моих данных представляют собой 64-битные целые числа. Я хотел бы отправить их в программу JavaScript, работающую на странице.

Однако, насколько я могу судить, целые числа в большинстве реализаций JavaScript представляют собой 32-битные величины со знаком.

Мои два варианта кажутся:

  1. Отправить значения в виде строк
  2. Отправлять значения в виде 64-битных чисел с плавающей запятой

Вариант (1) не идеален, но вариант (2) кажется гораздо менее совершенным (потеря данных).

Как вы справились с этой ситуацией?

  • горе программистам, которые попали на эту страницу! duhaime 06.04.2020

javascriptjson64-bit

Ответы

Ответ 1 · рейтинг 25 · Simon Howard

Кажется, это не столько проблема с 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];

Ответ 2 · рейтинг 20 · Arnaud Bouchez

На самом деле существует ограничение на уровне точности 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.Int64 или Edm.Decimal.

Что делает Twitter API в этом случае, так это добавляет конкретное поле ".._str": в JSON, как таковое:

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

Мне очень нравится этот вариант, так как он по-прежнему совместим с клиентами с поддержкой int64. На практике такой дублированный контент в JSON не сильно повредит, если его сдуть/заархивировать на уровне HTTP.

После передачи в виде строки вы можете использовать такие библиотеки, как strint - библиотека JavaScript для строковых целых чисел для обработки такие ценности.

Обновление. Новые версии движков JavaScript включают BigInt объектный класс, способный обрабатывать более 53-бит. На самом деле его можно использовать для произвольно больших целых чисел, поэтому он хорошо подходит для 64-битных целых чисел. Но при сериализации в формате JSON значение BigInt будет сериализоваться как строка JSON - как ни странно, но я думаю, в целях совместимости.

Ответ 3 · рейтинг 6 · David Leonard

Тип Javascript Number (64-битный IEEE 754) имеет только около 53 бит точности.

Но если вам не нужно выполнять сложение или умножение, вы можете сохранить 64-битное значение в виде 4-символьной строки, поскольку JavaScript использует UTF-16.

Например, 1 может быть закодировано как " ". Это имеет то преимущество, что сравнение значений (==, >, ‹) работает со строками, как и ожидалось. Также кажется простым писать битовые операции:

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

Ответ 4 · рейтинг 2 · olliej

Представление числа JS является стандартным ieee double, поэтому вы не можете представить 64-битное целое число. iirc вы получаете, возможно, 48 бит фактической точности int в двойном, но все биты JS уменьшаются до 32-битной точности (это то, что требует спецификация, ура!), поэтому, если вам действительно нужен 64-битный int в js, вам нужно будет реализовать свой собственный 64-битная библиотека встроенной логики.

Ответ 5 · Javier

Сам JSON не заботится об ограничениях реализации. ваша проблема в том, что JS не может обрабатывать ваши данные, а не протокол. Другими словами, ваш клиентский код JS должен использовать любой из этих несовершенных вариантов.

Ответ 6 · Desmond Coertzen

Это случилось со мной. Весь ад разразился при отправке больших целых чисел через json в JSON.parse. Я провел дни, пытаясь отладить. Проблема сразу же решилась, когда я передал значения в виде строк.

Используйте { "the_sequence_number": "20200707105904535" } вместо { "the_sequence_number": 20200707105904535 }

Что еще хуже, может показаться, что там, где реализован каждый JSON.parse, есть какая-то общая библиотека между Firefox, Chrome и Opera, потому что все они вели себя одинаково. Сообщения об ошибках Opera содержат ссылки на URL-адреса Chrome, почти как 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));

Поведение, которое я получил, было таким, когда математика указателя пошла ужасно плохо. Призраки вылетали из моей рабочей станции, сея хаос во сне. Теперь, когда я перешел на струны, они все изгнаны.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы