Кортеж повышения был бы моим предпочтительным вариантом для обобщенной системы возврата больше чем одного значения от функции.
Возможный пример:
include "boost/tuple/tuple.hpp"
tuple <int,int> divide( int dividend,int divisor )
{
return make_tuple(dividend / divisor,dividend % divisor )
}
Что вы видите здесь на самом деле эффект двух округлений. Числа в ECMAScript внутренне представлены с плавающей запятой двойной точности. Если для id
задано значение 714341252076979033
( 0x9e9d9958274c359
в шестнадцатеричном формате), фактически ему присваивается ближайшее представимое значение двойной точности, которое составляет 714341252076979072
( 0x9e9d9958274c380
). Когда вы распечатываете значение, оно округляется до 15 значащих десятичных цифр, что дает 14341252076979100
.
Это не вызвано этим парсером json. Просто попробуйте ввести 714341252076979033 в консоль fbug. Вы увидите тот же 714341252076979100.
Подробнее см. В этом сообщении в блоге: http://www.exploringbinary.com/print-precision-of-floating-point-integers-varies-too
JavaScript использует плавающую точку двойной точности значения, то есть общая точность 53 бита, но вам нужно
ceil(lb 714341252076979033) = 60
бит для точного представления значения.
Ближайшее точно представимое число - 714341252076979072
(запишите исходное число в двоичном формате, замените последнее 7 цифр с 0
и округлить в большую сторону, потому что самая высокая замещенная цифра была 1
).
Вы получите 714341252076979100
вместо этого числа, потому что ToString ()
, как описано в ECMA-262, §9.8.1 работает с степенями десяти, и с точностью до 53 бит все эти числа равны.
Вы переполняете емкость числового типа 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
-754, плавающий формат точки больше не может представлять каждое последовательное целое число. 9007199254740991 + 1
равно 9007199254740992
, но 9007199254740992 + 1
равно также 9007199254740992
, потому что 9007199254740993
не может быть представлен в формате. Следующим может быть 9007199254740994
. Тогда 9007199254740995
не может быть, но 9007199254740996
может.
Причина в том, что у нас закончились биты, поэтому у нас больше нет 1-го бита; бит младшего порядка теперь представляет кратные 2. В конце концов, если мы продолжим, мы потеряем этот бит и будем работать только с кратными 4. И так далее.
Ваши значения хорошо выше этого порога , и поэтому они округляются до ближайшего представимого значения.
Если вам интересны биты, вот что происходит: двоичное число с плавающей запятой двойной точности IEEE-754 имеет знаковый бит, 11 бит экспоненты (которая определяет общий масштаб числа как степень двойки [потому что это двоичный формат]) и 52 бита значимости (но формат настолько умен, что дает 53 бита точности из этих 52 бита). Использование экспоненты сложно ( описано здесь ), но в очень неопределенных терминах, если мы добавим единицу к показателю, значение значащей будет удвоено, так как показатель степени равен используется для степеней двойки (опять же, будьте осторожны, это не прямо, в этом есть ум).
Итак, давайте посмотрим на значение 9007199254740991
(также известное как 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)
Формат просто не может больше представлять нечетные числа, поскольку мы увеличиваем значение, экспонента слишком велика.
В конце концов, у нас заканчиваются значащие биты. снова и нужно увеличить показатель степени,
Проблема в том, что ваш номер требует большей точности, чем JavaScript.
Можете ли вы отправить число в виде строки? Разделены на две части?
JavaScript может обрабатывать только точные целые числа до примерно 9000 миллионов миллионов (это 9 с 15 нулями). Выше этого - мусор. Чтобы обойти эту проблему, используйте строки для хранения чисел. Если вам нужно выполнить математические вычисления с этими числами, напишите свои собственные функции или посмотрите, сможете ли вы найти для них библиотеку: я предлагаю первое, поскольку мне не нравятся библиотеки, которые я видел. Для начала ознакомьтесь с двумя моими функциями на , другой ответ .