Math.round Rounding Error

Try something like...

Math.round(num*100)/100


1) Multiple the original number by 10^x (10 to the power of x)
2) Apply Math.round() to the result
3) Divide result by 10^x

from: http://www.javascriptkit.com/javatutors/round.shtml

(to round any number to x decimal points)


This formula Math.round(num*100)/100 is not always good. Example

Math.round(0.145*100)/100 = 0.14

this is wrong, we want it to be 0.15

Explanation

The problem is that we have floats like that

0.145 * 100 = 14.499999999999998

step one

so If we round, we need to add a little bit to our product.

0.145 * 100 + 1e-14 = 14.500000000000009

I assume that sometimes the product might be something like 1.000000000000001, but it would not be a problem if we add to it, right?

step two

Calculate how much should we add?

We know float in java script is 17 digits.

let num = 0.145
let a = Math.round(num*100)/100
let b = a.toString().length
let c = 17-b-2
let result = Math.round(num*100 + 0.1**c)/100
console.log(result)
console.log('not - ' + a )

(-2) - is just to be sure we are not falling into the same trap of rounding.

One-liner:

let num = 0.145
let result = Math.round(num*100 + 0.1**(17-2-(Math.round(num*100)/100).toString().length))/100

Extras

Remember, that everything above is true for positive numbers. If you rounding negative number you would need to subtract a little bit. So the very final One-liner would be:

let num = -0.145
let result = Math.round(num*100 + Math.sign(num)*0.1**(17-2-(Math.round(num*100)/100).toString().length))/100

I realize this problem is rather old, but I keep running into it even 5 years after the question has been asked.

A working solution to this rounding problem I know of is to convert the number to a string, get the required precision number and round up or down using math rules.

An example where Math.round provides unexpected rounding and an example of string rounding can be found in the following fiddle: http://jsfiddle.net/Shinigami84/vwx1yjnr/

function round(number, decimals = 0) {
    let strNum = '' + number;
    let negCoef = number < 0 ? -1 : 1;
    let dotIndex = strNum.indexOf('.');
    let start = dotIndex + decimals + 1;
    let dec = Number.parseInt(strNum.substring(start, start + 1));
    let remainder = dec >= 5 ? 1 / Math.pow(10, decimals) : 0;
    let result = Number.parseFloat(strNum.substring(0, start)) + remainder * negCoef;
    return result.toFixed(decimals);
}
let num = 0.145;
let precision = 2;

console.log('math round', Math.round(num*Math.pow(10, precision))/Math.pow(10, precision));
// 0.145 rounded down to 0.14 - unexpected result
console.log('string round', round(num, precision));
// 0.145 rounded up to 0.15 - expected result

Math.round doesn't work properly here because 0.145 multiplied by 100 is 14.499999999999998, not 14.5. Thus, Math.round will round it down as if it was 14.4. If you convert it to a string and subtract required digit (5), then round it using standard math rules, you will get an expected result of 0.15 (actually, 0.14 + 0.01 = 0.15000000000000002, use "toFixed" to get a nice, round result).