Проблема неточных вычислений описана в статье справки https://elma365.com/ru/help/platform/js-imprecise-calculations.html
Также имеется разбор вопросов по округлению https://stackoverflow.com/questions/11832914/how-to-round-to-at-most-2-decimal-places-if-necessary
В связи с этим, при округлении «стандартными» способами могут возникать погрешности.
Например:
- для parseFloat("1.555").toFixed(2) результат будет 1.55, а не 1.56
- для Math.round(1.005 * 100) / 100 результат будет 1, а не 1.01
Минимизировать ошибку округления возможно при помощи использования константы Number.EPSILON.
Для удобства переиспользования округление вынесено в метод. На вход число для округления и количество знаков после запятой.
Код:
function mathRound(value: number, digits: number) {
if (!Number.isInteger(digits)) {
return NaN;
}
const round = 10 ** digits;
return Math.round((value + Number.EPSILON) * round) / round;
}
Использование Number.EPSILON также не даёт точного округления в некоторых случаях. Например, для 1.3549999999999998, результат будет 1.35, а не 1.36.
Более полным решением проблемы будет реализация алгоритма округления https://en.wikipedia.org/wiki/Rounding.
Либо использование соответствующей библиотеки.
Также один из вариантов решения рассматривается на китайской версии MDN.