Не уверен в специфике Java API, но общий способ сделать это - добавить групповую проверку на запрос / привязку.
То, что вы видите здесь, на самом деле является эффектом двух закруглений. Числа в ECMAScript представляют собой внутренне представленную точку с плавающей запятой с двойной точностью. Если для параметра id
установлено значение 714341252076979033
(0x9e9d9958274c359
в шестнадцатеричном формате), ему фактически присваивается ближайшее представимое значение двойной точности, которое равно 714341252076979072
(0x9e9d9958274c380
). Когда вы распечатываете значение, оно округляется до 15 значащих десятичных цифр, что дает 14341252076979100
.
JavaScript использует значения двойной точности с плавающей запятой, то есть полную точность 53 бит, но вам нужно
ceil(lb 714341252076979033) = 60
битов, чтобы точно представить это значение.
Ближайшая точно представимая число 714341252076979072
(записать исходный номер в двоичном формате, заменить последние 7 цифр на 0
и округлить, потому что наивысшая замещенная цифра была 1
).
Вы получите 714341252076979100
вместо этого числа, поскольку ToString()
, как описано ECMA-262, §9.8.1 работает с полномочиями в десять и по 53-битной точности, все эти числа равны.
JavaScript может обрабатывать только точные целые числа до примерно 9000 миллионов миллионов (это 9 с 15 нулями). Это выше, и вы получаете мусор. Обходите это, используя строки для хранения чисел. Если вам нужно сделать математику с этими цифрами, напишите свои собственные функции или посмотрите, можете ли вы найти библиотеку для них: я предлагаю первое, поскольку мне не нравятся библиотеки, которые я видел. Чтобы начать работу, см. Две мои функции в другом ответе .
Проблема в том, что ваш номер требует большей точности, чем JavaScript.
Можете ли вы отправить номер в виде строки? Разделяется в двух частях?
Вы переполняете возможности типа номера JavaScript, см. §8.5 спецификации для деталей. Эти идентификаторы должны быть строками.
Плавающая точка с двойной точностью IEEE-754 (тип номера, используемого JavaScript) не может точно представлять все числа (конечно). Известно, что 0.1 + 0.2 == 0.3
неверно. Это может повлиять на целые числа, так же как и на дробные числа; он запускается после того, как вы получите более 9,007,199,254,740,991 (Number.MAX_SAFE_INTEGER
).
Beyond Number.MAX_SAFE_INTEGER + 1
(9007199254740992
), формат с плавающей запятой IEEE-754 больше не может представлять каждое последовательное целое число. 9007199254740991 + 1
- 9007199254740992
, но 9007199254740992 + 1
также 9007199254740992
, потому что 9007199254740993
не может быть представлен в формате. Следующим, что может быть, является 9007199254740994
. Тогда 9007199254740995
не может быть, но 9007199254740996
может.
Причина в том, что у нас закончились биты, поэтому у нас больше нет 1-битного; бит младшего порядка теперь представляет кратность 2. В конечном счете, если мы продолжаем идти, мы теряем этот бит и работаем только в кратных 4. И так далее.
Ваши значения - хорошо выше этого порога, и поэтому они округляются до ближайшего представимого значения.
Если вам интересно узнать о битах, вот что происходит: двоичная двоичная двунаправленная плавающая переменная IEEE-754, номер точки имеет знаковый бит, 11 бит экспоненты (который определяет общий масштаб числа, как мощность 2 [потому что это двоичный формат]) и 52 бит значимости (но формат настолько умный, что он получает 53 бит точности из этих 52 бит). То, как используется показатель экспоненты, является сложным (, описанным здесь ), но в очень неопределенных терминах, если мы добавим его к экспоненте, значение знаменателя удваивается, так как показатель степени используется для степеней 2 (опять же, предостережение там, это не прямо, там есть умность).
Итак, давайте посмотрим на значение 9007199254740991
(aka, Number.MAX_SAFE_INTEGER
):
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− sign bit / +−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− exponent / / | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+− significand / / | / | 0 10000110011 1111111111111111111111111111111111111111111111111111 = 9007199254740991 (Number.MAX_SAFE_INTEGER)
Это значение экспоненты 10000110011
означает, что каждый раз, когда мы добавляем его к значению, число, представленное, увеличивается на 1 (целое число 1, мы потеряли способность представлять дробные числа намного раньше).
Но теперь эта значимость полна. Чтобы пройти мимо этого числа, нам нужно увеличить показатель, что означает, что если мы добавим его к значению, значение представленного числа увеличится на 2, а не 1 (поскольку показатель применяется к 2, база этого двоичное число с плавающей запятой):
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− sign bit / +−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− exponent / / | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+− significand / / | / | 0 10000110100 0000000000000000000000000000000000000000000000000000 = 9007199254740992 (Number.MAX_SAFE_INTEGER + 1)
Ну, это нормально, потому что 9007199254740991 + 1
равно 9007199254740992
. Но! Мы не можем представить 9007199254740993
. У нас закончились бит. Если мы добавим только 1 к значению, он добавит 2 к значению:
+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− sign bit / +−−−−−−−+−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− exponent / / | +−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−+− significand / / | / | 0 10000110100 0000000000000000000000000000000000000000000000000001 = 9007199254740994 (Number.MAX_SAFE_INTEGER + 3)
Формат просто не может представлять нечетные числа, поскольку мы увеличиваем значение, показатель слишком велик.
В конце концов, мы снова закончим значащие биты и должны увеличить экспоненту, поэтому мы можем только представить кратность 4. Затем умножить на 8. Затем умножим на 16. И так далее.
Это не вызвано этим парсером json. Просто попробуйте ввести 714341252076979033 в консоль fbug. Вы увидите тот же 714341252076979100.
Подробнее см. В этом блоге: http://www.exploringbinary.com/print-precision-of-floating-point-integers-varies-too