написать впереди
С изменением концепции потребления интернет-потребление стало неотъемлемой частью общественной жизни. При обеспечении безопасности потребителей и конфиденциальности пользователей точность также является важной частью. Только представьте, что подумает пользователь, когда он тратит деньги на продукт, а сумма расчета неверна? (Изучение спорта или WTF?), правильный плохой отзыв. Таким образом, не говоря уже о прилипчивости пользователей, удержание является проблемой. Когда Босс узнает об опыте пользователя, предполагается, что товарищи, предоставившие код, станут бывшими сотрудниками или умершими сотрудниками такими-то и такими-то. Я как отличный(ладжи)программист давно столкнулся с проблемой точного расчета,но поленился и не разобрался.До недавнего времени кто-то задавал мне сопутствующие вопросы,и вдруг я почувствовал необходимость написать о моем понимании точного расчета в js
Сцена ролловера, вычисленная в JavaScript
Ближе к дому, книга продолжает вышеизложенное, давайте сначала перейдем к простому (landajie) 🌰, чтобы показать общую работу js-вычислений.
Как JavaScript представляет числа?
JavaScript использует тип Number для представления чисел (как целых, так и с плавающей запятой), следующих заIEEE 754Стандартный Представляет число до 64 бит
В частности, посмотрите на цифровые изображения в памяти представления
- Бит 0: бит знака, 0 означает положительное число, 1 означает отрицательное число (ы)
- Биты с 1 по 11: сохранить экспоненциальную часть (e)
- Биты с 12 по 63: сохраняют дробную часть (т.е. значащие цифры) f
Теперь, когда мы здесь, позвольте мне немного рассказать вам о популярной науке: максимальное безопасное количество js равноNumber.MAX_SAFE_INTEGER == Math.pow(2,53) - 1, а не Math.pow(2,52) - 1, почему? Разве часть мантиссы не составляет всего 52 бита?
Это связано с тем, что двоичное представление значащих цифр всегда имеет вид 1.xx...xx, а первая цифра части мантиссы f в сокращенной форме по умолчанию равна 1 (опускается и не записывается, xx..xx часть мантиссы f, максимум 52 бита). Таким образом, JavaScript предоставляет значащие цифры до 53 двоичных цифр (последние 52 бита 64-битной с плавающей запятой + 1 бит опущен).
Просто подтвердите
Что произошло во время операции?
Во-первых, компьютеры не могут напрямую оперировать десятичными числами, что определяется физическими характеристиками оборудования. Эта операция делится на две части:Сначала преобразуйте его в соответствующий двоичный файл по стандарту IEEE 754, а затем действуйте по порядку.
По этой идее анализируем процесс работы 0.1+0.2
1. Базовое преобразование
0.1 и 0.2 будут бесконечно зацикливаться после преобразования в двоичный
0.1 -> 0.0001100110011001...(无限循环)
0.2 -> 0.0011001100110011...(无限循环)
Однако из-за ограничения цифр мантиссы IEEE 754 необходимо обрезать лишние биты позади (в этой статье используется этотВеб-сайтВизуально отображать двоичное представление чисел с плавающей запятой в памяти)
0.1
0.2
Вот еще немного знаний
Итак, почему x = 0,1, чтобы получить 0,1?
Это потому, что это не настоящий 0.1 0.1. Разве это не бессмысленно? Но подождите, позвольте мне объяснить
Стандарт предусматривает, что фиксированная длина мантиссы f составляет 52 бита плюс пропущенный, эти 53 бита являются диапазоном точности JS. Он может представлять до 2 ^ 53 (9007199254740992), а длина равна 16, поэтому вы можете использовать toPrecision (16) для точных операций, а избыточная точность будет автоматически округлена в большую сторону.
0.10000000000000000555.toPrecision(16)
// 返回 0.1000000000000000,去掉末尾的零后正好为 0.1
// 但来一个更高的精度:
0.1.toPrecision(21) = 0.100000000000000005551
Вот почему 0,1 может быть равно 0,1. хорошо давай
2. Операции в обратном порядке
Поскольку количество разрядов в показателе степени не совпадает, операцию необходимо выполнять в порядке порядка, эта часть также может привести к потере точности.
В соответствии с двумя вышеуказанными шагами (включая потерю точности двух шагов) окончательный результат равен
0.0100110011001100110011001100110011001100110011001100
После преобразования результата в десятичный вид он равен 0,300000000000000004, поэтому есть предыдущая операция «показать»: 0,1 + 0,2 != 0,3
так:
Потеря точности может произойти во время базового преобразования и операций упорядочения.
Потеря точности может произойти во время базового преобразования и операций упорядочения.
Потеря точности может произойти во время базового преобразования и операций упорядочения.
Пока на этих двух шагах есть потеря точности, результаты вычислений будут смещены.
Как решить проблему точности?
1. Преобразование чисел в целые числа
Это самый простой способ думать, и относительно простой
function add(num1, num2) {
const num1Digits = (num1.toString().split('.')[1] || '').length;
const num2Digits = (num2.toString().split('.')[1] || '').length;
const baseNum = Math.pow(10, Math.max(num1Digits, num2Digits));
return (num1 * baseNum + num2 * baseNum) / baseNum;
}
Но этот метод по-прежнему не годится для больших чисел.
2. Трехсторонняя библиотека
Это более комплексный подход.Я рекомендую 2 библиотеки, с которыми я обычно соприкасаюсь.
1).Math.js
Обширная математическая библиотека, посвященная JavaScript и Node.js. Поддерживает числа, большие числа (числа за пределами безопасных чисел), комплексные числа, дроби, единицы измерения и матрицы. Мощный и простой в использовании.
Официальный сайт:mathjs.org/
Гитхаб:GitHub.com/Джо сказал Чонгук/нет…
2).big.js
Официальный сайт:mikemcl.github.io/big.js
Гитхаб:GitHub.com/Mike MC приближается/закрывается…
3) Несколько, не перечисляемые по одному
Эти библиотеки очень мощные и могут удовлетворить различные потребности, но во многих случаях проблему, которую можно решить с помощью функции, не нужно решать, обращаясь к библиотеке классов.
Вышеизложенное - это мое понимание точного расчета js, я надеюсь, что это может вам помочь.
При перепечатке обязательно указывать источник, спасибо. В статье есть упущения и поверхностность, прошу меня поправить
иллюстрировать
Прочтите комментарии, и многие люди скажут: «Другие следуют».IEEE 754Стандартный язык также имеет эту проблему, я знаю, что другие языки также имеют эту проблему, но эта статья анализируется с помощью js в качестве отправной точки, поэтому не беспокойтесь о том, какой язык, в центре внимания статьи не язык, Спасибо
Прочтите комментарии, и многие люди скажут: «Другие следуют».IEEE 754Стандартный язык также имеет эту проблему, я знаю, что другие языки также имеют эту проблему, но эта статья анализируется с помощью js в качестве отправной точки, поэтому не беспокойтесь о том, какой язык, в центре внимания статьи не язык, Спасибо
Прочтите комментарии, и многие люди скажут: «Другие следуют».IEEE 754Стандартный язык также имеет эту проблему, я знаю, что другие языки также имеют эту проблему, но эта статья анализируется с помощью js в качестве отправной точки, поэтому не беспокойтесь о том, какой язык, в центре внимания статьи не язык, Спасибо