Вычитание длинных чисел в javascript
-
20-09-2019 - |
Вопрос
Почему q == 0 в следующем скрипте?
<script>
var start = 1234567890123456789;
var end = 1234567890123456799;
var q = end - start;
alert(q);
</script>
Я бы подумал, что результат должен быть равен 10.Как правильно вычесть эти два числа?
Решение
Потому что числа в JavaScript имеют плавающую точку.Они имеют ограниченную точность.
Когда JavaScript видит очень длинное число, он округляет его до ближайшего числа, которое оно может представить в виде 64-битного числа с плавающей запятой.В вашем сценарии start
и end
округлить до одного и того же значения.
alert(1234567890123456789); // says: 1234567890123456800
alert(1234567890123456799); // says: 1234567890123456800
Не существует встроенного способа выполнения точных арифметических действий с большими целыми числами, но вы можете использовать библиотеку BigInteger, например Вот этот.
Другие советы
Джейсон уже написал причину.В качестве решения вы можете получить библиотеку Javascript BigInt по адресу http://www-cs-students.stanford.edu/~tjw/jsbn/
const subtract = (a, b) => [a, b].map(n => [...n].reverse()).reduce((a, b) => a.reduce((r, d, i) => {
let s = d - (b[i] || 0)
if (s < 0) {
s += 10
a[i + 1]--
}
return '' + s + r
}, '').replace(/^0+/, ''))
Лучше использовать для этих целей библиотеку больших целых чисел, чтобы обрабатывать все различные тестовые случаи.
Это только для общего случая, который вы можете использовать....
Это объясняется в Документация JavaScript:
Согласно стандарту ECMAScript, существует только один числовой тип: значение 64-битного двоичного формата двойной точности IEEE 754 в двоичном формате (числа между
-(2
53
-1)
и2
53
-1
). Для целых чисел не существует определенного типа.
Страница в Википедии о формат с плавающей запятой двойной точности объясняет:
Между
2
52
= 4,503,599,627,370,496
и2
53
= 9,007,199,254,740,992
представимые числа - это в точности целые числа.Для следующего диапазона, начиная с2
53
Для2
54
, все умножается на2
, таким образом, представимые числа являются четными и т.д.
(Все целые числа, меньшие 2
52
представлены точно.)
1234567890123456789
и 1234567890123456799
больше, чем 2
60
= 1152921504606846976
.При такой величине только около 1% целых чисел хранятся в точности с использованием формата с плавающей запятой двойной точности.
Эти два файла не могут быть сохранены в точности.Они оба округлены до 1234567890123456800
.
Тот самый Документация JavaScript также объясняется, как определить, точно ли сохранено целое число:
[...] и начиная с ECMAScript 6, вы также можете проверить, находится ли число в диапазоне чисел с плавающей запятой двойной точности, используя
Number.isSafeInteger()
а такжеNumber.MAX_SAFE_INTEGER
иNumber.MIN_SAFE_INTEGER
.За пределами этого диапазона целые числа в JavaScript больше не безопасны и будут аппроксимацией значения с плавающей запятой двойной точности.