Некоторые из моих данных представляют собой 64-битные целые числа. Я хотел бы отправить их в программу JavaScript, работающую на странице.
Однако, насколько я могу судить, целые числа в большинстве реализаций JavaScript представляют собой 32-битные числа со знаком.
Кажется, у меня есть два варианта:
Вариант (1) не идеален, но вариант (2) кажется гораздо менее идеальным (потеря данных).
Как вы справились с этой ситуацией?



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Сам JSON не заботится об ограничениях реализации. ваша проблема в том, что JS не может обрабатывать ваши данные, а не протокол. Другими словами, ваш код JS-клиента должен использовать любой из этих несовершенных вариантов.
Кажется, это меньше проблема с 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];
Когда я пробую «input_value >> 32», я просто возвращаю «input_value», как будто 32 бита просто полностью переносятся. ">>>" имеет тот же эффект. Тем не менее, когда я пробую «Math.floor (input_value / 4294967296)» (4294967296 = Math.pow (2, 32)), я получаю старшую 32-битную часть «input_value»; Что мне не хватает?
Вы не говорите, какой язык используете, поэтому я предполагаю, что вы используете Java. Является ли input_value длинным (например, 64-битным целым числом)? Если это int (32-битное целое число), то сдвиг влево на 32 бита работать не будет.
извините за это .. Я должен был быть откровенным. Я использую javascript (в nodejs) и был действительно удивлен, увидев, что сдвиг на 32 бита вправо каким-то образом дал мне то же число. Я не совсем понимаю все неявные преобразования типов в javascript и их базовые представления.
Это по-прежнему является проблема JSON, а не проблема Javascript, поскольку JSON не поддерживает целые числа с более чем 9 десятичными цифрами. Если бы это было так, реализация Javascript была бы вынуждена обеспечивать его поддержку каким-то образом под капотом.
@LightnessRacesinOrbit, похоже, я не могу найти ссылку на оператор 9 десятичных цифр. Это в какой-то спецификации?
@akhaku: Это версия спецификации (RFC 4627 и www.json.org), которую я придумал в своей голове, когда неправильно истолковал грамматику. :)
Представление числа JS - это стандартное двойное значение ieee, поэтому вы не можете представить 64-битное целое число. iirc вы получаете, возможно, 48 бит фактической точности int в двойном, но все битопы JS уменьшаются до 32-битной точности (это то, что требует спецификация. yay!), поэтому, если вам действительно нужен 64-битный int в js, вам нужно будет реализовать свой собственный 64-битная логическая библиотека int.
53 бита всегда, без учета знака.
Тип 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;
}
Это умный способ сэкономить на байтах, передаваемых по сети, и при этом иметь возможность более или менее считывать число. Мне было бы интересно узнать, есть ли у этого подхода какие-то подводные камни.
Фактически существует ограничение на уровне точности JavaScript / ECMAScript 53-битным для целых чисел (они хранятся в мантиссе «двойного» 8-байтового буфера памяти). Таким образом, передача больших чисел в виде JSON не будет десериализована, как ожидалось клиентом JavaScript, который усечет их до своего 53-битного разрешения.
> parseInt("10765432100123456789")
10765432100123458000
См. Функцию Константа Number.MAX_SAFE_INTEGER и Number.isSafeInteger():
The
MAX_SAFE_INTEGERconstant has a value of9007199254740991. The reasoning behind that number is that JavaScript uses double-precision floating-point format numbers as specified in IEEE 754 and can only safely represent numbers between-(2^53 - 1)and2^53 - 1.Safe in this context refers to the ability to represent integers exactly and to correctly compare them. For example,
Number.MAX_SAFE_INTEGER + 1 === Number.MAX_SAFE_INTEGER + 2will evaluate totrue, which is mathematically incorrect. SeeNumber.isSafeInteger()for more information.
Из-за разрешения чисел с плавающей запятой в 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 - как ни странно, но для совместимости, я думаю.
Отличное объяснение. Я только что столкнулся с этим с интерфейсом JS и серверной частью веб-API C#. Мой HttpResponseMessage сериализует мои объекты (которые содержат длинные идентификаторы), и они усекаются. Что было действительно странно, они не усекались, пока не попали в браузер. Если я создал ответ, а затем проанализировал контент перед его отправкой, идентификаторы не были усечены. Только когда браузер получил и проанализировал ответ, он волшебным образом усек. Ваше объяснение помогло мне понять, почему. Спасибо! В итоге я зарегистрировал собственный конвертер для длинных типов.
Это случилось со мной. При отправке больших целых чисел через json в JSON.parse разразился ад. Я потратил дни на отладку. Проблема сразу же решена, когда я передал значения в виде строк.
Использовать
вместо
{ "the_sequence_number": "20200707105904535" }{ "the_sequence_number": 20200707105904535 }
Что еще хуже, может показаться, что там, где реализован каждый JSON.parse, есть некоторая общая библиотека между Firefox, Chrome и Opera, потому что все они вели себя точно так же. Сообщения об ошибках Opera содержат ссылки на URL-адреса Chrome, почти как WebKit, используемый браузерами.
console.info('event_listen[' + global_weird_counter + ']: to be sure, server responded with [' + aresponsetxt + ']');
var response = JSON.parse(aresponsetxt);
console.info('event_listen[' + global_weird_counter + ']: after json parse: ' + JSON.stringify(response));
Я получил такое поведение, когда математика с указателями пошла ужасно плохо. Призраки вылетали из моего рабочего места, сея хаос во сне. Они все изгнаны теперь, когда я перешел на струнные.
Разве это не проблема Javascript, а не JSON.
Видно так. Прочтите stackoverflow.com/questions/9643626/…
горе программистам, попавшим на эту страницу!