написать впереди
С изменением концепции потребления интернет-потребление стало неотъемлемой частью общественной жизни. При обеспечении безопасности потребителей и конфиденциальности пользователей точность также является важной частью. Только представьте, что подумает пользователь, когда он тратит деньги на продукт, а сумма расчета неверна? (Изучение спорта или WTF?), правильный плохой отзыв. Таким образом, не говоря уже о прилипчивости пользователей, удержание является проблемой. Когда Босс узнает об опыте пользователя, предполагается, что товарищи, предоставившие код, станут бывшими сотрудниками или умершими сотрудниками такими-то и такими-то. Я как отличный(ладжи)программист давно столкнулся с проблемой точного расчета,но поленился и не разобрался.До недавнего времени кто-то задавал мне сопутствующие вопросы,и вдруг я почувствовал необходимость написать о моем понимании точного расчета в js
Сцена ролловера, вычисленная в JavaScript
Ближе к дому, книга продолжает вышеизложенное, давайте сначала перейдем к простому (landajie) 🌰, чтобы показать общую работу js-вычислений.
Этот вид подвопроса, 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 в качестве отправной точки, поэтому не беспокойтесь о том, какой язык, в центре внимания статьи не язык, Спасибо