Math.round Rounding Error
Asked Answered
I

4

7

I Want to round 1.006 to two decimals expecting 1.01 as output

When i did

var num = 1.006;
alert(Math.round(num,2)); //Outputs 1 
alert(num.toFixed(2)); //Output 1.01

Similarly,

var num =1.106;
alert(Math.round(num,2)); //Outputs 1
alert(num.toFixed(2));; //Outputs 1.11

So

  • Is it safe to use toFixed() every time ?
  • Is toFixed() cross browser complaint?

Please suggest me.

P.S: I tried searching stack overflow for similar answers, but could not get proper answer.

EDIT:

Why does 1.015 return 1.01 where as 1.045 returns 1.05

var num =1.015;
alert(num.toFixed(2)); //Outputs 1.01
alert(Math.round(num*100)/100); //Outputs 1.01

Where as

var num = 1.045;
alert(num.toFixed(2)); //Outputs 1.04
alert(Math.round(num*100)/100); //Outputs 1.05
Intimacy answered 27/2, 2013 at 17:39 Comment(6)
Math.round rounds to the nearest integer.Brae
@Jrod: If you refer this fiddle it outputs decimal values alsoIntimacy
@nlsbshtr: Thanks for pointing it, can you check my edit and help me with second questionIntimacy
@Intimacy your edit has to do with the fact that some decimal numbers cannot be represented to perfect precision. Specifically in your case, 1.015*100 gives you 101.49999999999999 instead of 101.5, causing it to round down instead of up.Monkfish
@jbabey:Thanks for you comment, it solved my problem.Intimacy
@Intimacy When you multiple by 100 you are changing everything. 1.006 x 100 = 100.6. 100.6 rounded to the nearest integer is 101. 101 divided by 100 is 1.01. The round function is not outputting decimals.Brae
H
4

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)

Holocrine answered 27/2, 2013 at 17:43 Comment(7)
Thanks for your answer, BTW how did you arive at 100?Intimacy
@Intimacy 10^x gives you x decimal points, 10^2 = 100 = 2 decimal points.Monkfish
@jbabey: Thanks for your answer, can you check my edit and can you explain me what is correct approach for roundingIntimacy
@Intimacy instead of round you can use ceil or floor, ceil to get rounded up and floor to round down, thats more specific than roundEscadrille
@Ark:Thanks for your comment it did the trick, thank you so muchIntimacy
@nlsbshtr: it seems problem with floating point errors.Intimacy
You are wrong. Example: Math.round(4.975 * 100)/100 = 4.97 when it should be 4.98Sackey
S
3

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
Sackey answered 4/7, 2018 at 5:48 Comment(0)
C
2

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).

Cantina answered 13/6, 2018 at 10:50 Comment(3)
I confirm, your way is working. Thank you for sharing. However, I bet my solution is better :)Sackey
I'm sorry, but your solution does not work for negative numbers.Sackey
@YevgeniyAfanasyev Updated the code to work with negative numbers.Cantina
G
0

Alternative solution that doesn't involve number to string conversion:

Math.round(Math.round(n * 1000) / 10) / 100

It's specific to 2 decimals, but you could also generalize it if needed.

In case of negative numbers, it rounds .005 up towards 0, so -0.145 becomes -0.14, which may or may not be what you want.

Let me know if you find a case where this doesn't work correctly.

Gaskin answered 18/3, 2024 at 8:55 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.