Усі числа в JavaScript (крім BigInt) - 64-бітні числа з плаваючою комою за стандартом IEEE 754. Більшість десяткових дробів, як 0.1, у двійковій системі - нескінченні дроби, тож зберігаються з крихітною похибкою.
0.1 + 0.2; // 0.30000000000000004
0.1 + 0.2 === 0.3; // false
1.005 * 100; // 100.49999999999999
Це не баг JavaScript - так само поводяться float у PHP, Python, Java.
Як порівнювати дроби: з допуском:
Math.abs(0.1 + 0.2 - 0.3) < Number.EPSILON; // true
Як рахувати гроші:
- У найменших одиницях - копійках, як цілі числа:
1999замість19.99. Цілі числа доNumber.MAX_SAFE_INTEGER(≈ 9 квадрильйонів) представлені точно. - Округлення - явне й в одному місці:
Math.round(price * quantity). - Для складних розрахунків (відсотки, курси, розподіл) - бібліотеки десяткової арифметики (
decimal.js,big.js,dinero.js). - Показ користувачу - через
Intl.NumberFormat:
new Intl.NumberFormat('uk-UA', { style: 'currency', currency: 'UAH' }).format(1999 / 100);
// '19,99 ₴'
toFixed() - для показу, не для розрахунків: він повертає рядок і сам округлює з тією ж похибкою ((1.005).toFixed(2) дає '1.00').