sindresorhus/round-to
The issue has been closed
Floating-point roundoff errors #20
amrali-eg posted onGitHub
I found these bugs in the code:
roundTo(0.597/6, 3) === 0.1
// false
roundTo.up((0.1+0.2)*10, 0) === 3
// false
roundTo.down((0.1+0.7)*10, 0) === 8
// false
I suggest to use the toPrecision() method to preround the result to 15 significant digits. This will strip the floating-point round-off errors in the intermediate calculations.
Please refer to my answer on stackoverflow https://stackoverflow.com/a/48764436
'use strict';
function round(method, number, precision) {
if (typeof number !== 'number') {
throw new TypeError('Expected value to be a number');
}
if (precision === Infinity) {
return number;
}
if (!Number.isInteger(precision)) {
throw new TypeError('Expected precision to be an integer');
}
const isRoundingAndNegative = method === 'round' && number < 0;
if (isRoundingAndNegative) {
number = Math.abs(number);
}
/*
let exponent;
[number, exponent] = `${number}e`.split('e');
let result = Math[method](`${number}e${Number(exponent) + precision}`);
[number, exponent] = `${result}e`.split('e');
result = Number(`${number}e${Number(exponent) - precision}`);
*/
let power = Math.pow(10, precision);
// preround the result to 15 significant digits to strip the floating-point
// round-off errors in the intermediate calculations.
let result = Math[method](+(number * power).toPrecision(15)) / power;
if (isRoundingAndNegative) {
result = -result;
}
return result;
}
module.exports = round.bind(undefined, 'round');
module.exports.up = round.bind(undefined, 'ceil');
module.exports.down = round.bind(undefined, 'floor');