Разработка решений на платформе ELMA365 / Неточные вычисления в JavaScript

Неточные вычисления в JavaScript

Вычисление дробного числа в системе определяется особенностями исполнения языка JavaScript в браузере пользователя и в NodeJS на сервере.

В JavaScript число представлено в виде 64-битного формата IEEE-754, т. е. хранит значение с плавающей точкой, что может приводить к неточным вычислениям.

Например, следующее сравнение будет определено в JavaScript как ложное:

alert( 0.1 + 0.2 == 0.3 ); // false

Это связано с тем, что значение 0,3 в JavaScript вычисляется следующим образом:

alert( 0.1 + 0.2 ); // 0.30000000000000004

Происходит так потому, что число хранится в памяти как последовательность бит — единиц и нулей. И дроби в такой двоичной системе становятся бесконечной дробью.

В JavaScript не хранятся точные значения 0.1 или 0.2. Числовой формат IEEE-754 округляет такие дроби до ближайшего возможного числа, например:

alert( 0.1.toFixed(20) ); // 0.10000000000000000555

Когда мы суммируем две дроби, их «неточности» тоже суммируются.

Отметим, что ошибка в точности вычислений для чисел с плавающей точкой сохраняется в любом языке, где используется формат IEEE-754, включая PHP, Java, C, Perl, Ruby.

Как решить проблему вычисления дробей

Можно попробовать полностью отказаться от дробей или использовать следующие способы.

  1. Округлить результат вычисления с помощью метода toFixed(n):

let sum = 0.1 + 0.2;
alert( sum.toFixed(2) ); // 0.30

Метод toFixed(n) всегда возвращает строку, поэтому вы получите результат с заданным количеством цифр в десятичной части.

  1. Временно умножить число на 100 (или большее), чтобы привести его к целому. Затем выполнить математические действия и разделить обратно на 100. Суммируя целые числа, вы уменьшаете погрешность, но она всё равно появляется при финальном делении:

alert( (0.1 * 10 + 0.2 * 10) / 10 ); // 0.3
alert( (0.28 * 100 + 0.14 * 100) / 100); // 0.4200000000000001

Таким образом, метод умножения и деления уменьшает погрешность, но полностью не решает её.