Если я спрошу вас, что такое 0,1 + 0,2? Вы можете непонимающе посмотреть на меня: 0,1 + 0,2 = 0,3 Ах, вам еще нужно спрашивать? На такой педиатрический вопрос могут ответить даже дети в детском саду. Но знаете, та же проблема на языке программирования может оказаться не такой простой, как себе представлялось.
Не верите? Давайте сначала посмотрим на фрагмент JS.
вар numA = 0,1;
вар numB = 0,2;
Предупреждение ((numA + numB) === 0,3);
Результат выполнения является ложным. Да, когда я впервые увидел этот код, я принял как должное его истинность, но результаты выполнения меня удивили. Неправильный ли у меня метод открытия? Нет, нет. Давайте попробуем еще раз выполнить следующий код и узнаем, почему результат ложный.
вар numA = 0,1;
вар numB = 0,2;
предупреждение (числоA + числоB);
Получается, что 0,1+0,2=0,30000000000000004. Разве это не странно? Фактически, для четырех арифметических операций с числами с плавающей запятой почти во всех языках программирования возникают проблемы, подобные ошибкам точности. Однако в таких языках, как C++/C#/Java, методы инкапсулированы, чтобы избежать проблем с точностью. а JavaScript является слабым типом. Язык не имеет строгого типа данных для чисел с плавающей запятой с точки зрения проектирования, поэтому проблема ошибок точности особенно заметна. Разберем, почему возникает такая ошибка точности и как ее исправить.
Прежде всего, нам нужно подумать о, казалось бы, педиатрической проблеме 0,1 + 0,2 с компьютерной точки зрения. Мы знаем, что компьютеры могут читать двоичные, а не десятичные числа, поэтому давайте сначала преобразуем 0,1 и 0,2 в двоичные и посмотрим:
0,1 => 0,0001 1001 1001 1001… (бесконечный цикл)
0,2 => 0,0011 0011 0011 0011… (бесконечный цикл)
Десятичная часть числа двойной точности с плавающей запятой поддерживает до 52 бит, поэтому после сложения этих двух мы получаем строку 0,0100110011001100110011001100110011001100110011001100. Двоичное число усекается из-за ограничения количества десятичных знаков чисел с плавающей запятой. На данный момент мы преобразуем его в десятичное, и оно становится 0,30000000000000004.
Вот и все, а как решить эту проблему? Мне нужен результат: 0,1 + 0,2 === 0,3 Ач! ! !
Одно из самых простых решений — указать четкие требования к точности. В процессе возврата значения компьютер будет автоматически округлять, например:
вар numA = 0,1;
вар numB = 0,2;
alert( parseFloat((numA + numB).toFixed(2)) === 0.3 );
Но очевидно, что это не метод раз и навсегда. Было бы здорово, если бы существовал метод, который мог бы помочь нам решить проблему точности этих чисел с плавающей запятой. Давайте попробуем этот метод:
Math.formatFloat = функция (f, цифра) {
var m = Math.pow(10, цифра);
вернуть parseInt(f * m, 10)/m;
}
вар numA = 0,1;
вар numB = 0,2;
alert(Math.formatFloat(numA + numB, 1) === 0,3);
Что означает этот метод? Чтобы избежать различий в точности, нам нужно умножить вычисляемое число на 10 в n-й степени, преобразовать его в целое число, которое компьютер может точно распознать, а затем разделить его на 10 в n-й степени. языки программирования обрабатывают разницу в точности, мы будем использовать ее для устранения ошибки точности чисел с плавающей запятой в JS.
Если кто-то в следующий раз спросит вас, чему равно 0,1 + 0,2, будьте осторожны с ответом! !