Round Decimal Places in JavaScript - The Reliable Way

Many times I've had to round numbers in JavaScript. It's common to always get a code snippet on the Internet.

But even the simplest rounding methods can have serious accuracy problems. Let's figure out how to round to N decimal places reliably in JavaScript.

To round a decimal number to 2 decimal places using JavaScript, we can use Math.round(decimal * 100) / 100, but this method ends up falling into the precision limitations of the language.

This is a standard and quite an effective way of rounding off a decimal number, but you should know that it's not a reliable method.

Full method for rounding numbers

As a short answer, I have at least two one-line solutions, but unfortunately, they are not at all accurate. And that's because of the binary nature of decimal numbers.

JavaScript uses the pattern IEE 745 to work with floating-point. When an arithmetic operation is performed on two float or double numbers, rounding is performed to plus or minus in the last square (bit), where the space allocated to represent that number ends.

That's why in JavaScript we have bizarre results for some simple operations, for example:

const num = 0.2 + 0.4;

console.log(0.6 == num); // false

console.log(num); // 0.6000000000000001

In the native Math.round or toFixed method we will also find the same problem when rounding to N decimal places.

Take a look at the function below that works accurately, brought by A Kunin

const round = (num, places) => {
	if (!("" + num).includes("e")) {
		return +(Math.round(num + "e+" + places) + "e-" + places);
	} else {
		let arr = ("" + num).split("e");
		let sig = ""
		if (+arr[1] + places > 0) {
			sig = "+";
		}

		return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + places)) + "e-" + places);
	}
}

console.log(round(1.005, 2)); // 1.01

In this function, we use the exponential notation (e+, e-) to work with the decimal value. In this way, we avoid the precision problem explained above.

But if you don't care so much about the JavaScript precision flaws, you can have this much simpler solution that uses a one-liner:

const round = (num, places) => {
	return +(parseFloat(num).toFixed(places));
}

console.log(round(1.005, 2)); // 1 - Precision flaw
console.log(round(1.0051, 2)); // 1.01

The function above uses the toFixed method, which ends up returning a string, but we use the + in front, that works the same way as doing Number(num).

How to format decimal numbers

To format numbers, dates and times for the standard used in different countries we always have to make some adaptation.

Fortunately, in JavaScript there is a very easy way to change the formatting for thousand separators and decimal separators:

// Let's say you want the default format, but with the thousand separator
(1234.5).toLocaleString('en-US'); // 1,234.5

// Zerofill for 2 decimal places
(1234.5).toLocaleString('en-US', { minimumFractionDigits: 2 }); // 1,234.50

// Currency format USD + 2 decimal places
// $1,234.50
(1234.5).toLocaleString('en-US', { minimumFractionDigits: 2, style: 'currency', currency: 'USD' });

Did you find this helpful?

Ricardo Metring

Ricardo Metring

Full stack web developer and co-founder at Criar.io.
I've worked for over 10 years with software development. I'm constantly curious and learning.

Linkedin     Github

Related articles