I wanted something concise and accurate with a good combination of readable and speed. After reading all the answers to this question, and this particularly helpful answer in a similar question, this is my solution.
const round = (numberToRound, digits = 0, toFixed = false) => {
const precision = 10 ** digits;
const n = numberToRound * precision * (1 + Number.EPSILON);
const roundedNumber = Math.round(n) / precision;
return toFixed ? roundedNumber.toFixed(digits) : roundedNumber;
};
// rounding by half
console.log(round(0.5));
console.log(round(-0.5));
// fixed decimals
console.log(round(0.5, 2), '( Type:',typeof round(0.5, 2), ')');
console.log(round(0.5, 2, true), '( Type:',typeof round(0.5, 2, true), ')');
console.log(round(-0.5, 2), '( Type:',typeof round(-0.5, 2), ')');
console.log(round(-0.5, 2, true), '( Type:',typeof round(-0.5, 2, true), ')');
// edge cases
console.log(round(1.005, 2) === 1.01);
console.log(round(-1.005, 2) === -1.01);
console.log(round(39.425, 2) === 39.43);
console.log(round(-39.425, 2) === -39.43);
console.log(round(1234.00000254495, 10) === 1234.000002545);
console.log(round(-1234.00000254495, 10) === -1234.0000025449);
// edge cases from other answer's comments.
console.log(round(859.385, 2));
console.log(round(859.3844, 2));
console.log(round(0.000000015, 8))
console.log(round(35.855, 2));
I don't love toFixed as a boolean parameter but it works for now.