How to use Javascript to round at most 2 decimal places, if necessary?
With my years of experience in JavaScript, I’ve found that rounding numbers to two decimal places can be tricky. One straightforward approach is to use Math.round()
:
Math.round((num + Number.EPSILON) * 100) / 100
This method ensures accurate rounding for numbers like 1.005.
I’ve been working with JavaScript for quite some time, and if you’re dealing with a string value, you can use parseFloat
:
parseFloat("123.456").toFixed(2);
For numeric values, toFixed()
works well:
var numb = 123.23454;
numb = numb.toFixed(2);
One thing to watch out for is that toFixed()
can result in strings like ‘1.50’ instead of ‘1.5’. You can convert it back to a number using the +
sign:
var numb = 1.5;
numb = +numb.toFixed(2);
However, both Math.round()
and toFixed()
have their quirks. For example:
Math.round(1.005 * 100) / 100; // Returns 1 instead of 1.01
parseFloat("1.555").toFixed(2); // Returns 1.55 instead of 1.56
Floating-point precision issues can lead to unexpected results. That’s why I sometimes prefer using a custom function or pulling pre-rounded values from the backend.
Hey Alveera Khan,
Solution 1 works great, @shashank_watak .
Here is a shorter version that also:
a) Handles uppercase “E” (since “1.23E10” is valid input) b) Handles negative scales function roundNumberV1(num, scale) { [base, exp = 0] = (“” + num).toLowerCase().split(“e”); return +(Math.round(+base + “e” + (+exp + scale)) + “e” + -scale); }
Well just to add up there are other ways to try it too for decimal rounding is by scaling: round(num * p) / p
Some of the ways are:
Naive Implementation
The naive approach for rounding decimal numbers can be inconsistent due to floating-point precision issues. Here’s the naive function:
function naiveRound(num, decimalPlaces = 0) {
var p = Math.pow(10, decimalPlaces);
return Math.round(num * p) / p;
}
console.log(naiveRound(1.245, 2)); // 1.25 correct
console.log(naiveRound(1.255, 2)); // 1.25 incorrect
console.log(naiveRound(1.005, 2)); // 1.00 incorrect
console.log(naiveRound(2.175, 2)); // 2.17 incorrect
console.log(naiveRound(5.015, 2)); // 5.01 incorrect
Better Implementations
To address the inconsistencies of naive rounding, here are some improved implementations:
1. Exponential Notation
This method uses exponential notation to handle rounding correctly:
function round(num, decimalPlaces = 0) {
num = Math.round(num + "e" + decimalPlaces);
return Number(num + "e" + -decimalPlaces);
}
console.log(round(0.5)); // 1
console.log(round(-0.5)); // 0
console.log(round(1.005, 2)); // 1.01
console.log(round(2.175, 2)); // 2.18
console.log(round(5.015, 2)); // 5.02
console.log(round(-1.005, 2)); // -1
console.log(round(-2.175, 2)); // -2.17
console.log(round(-5.015, 2)); // -5.01
2. Approximate Rounding
This function uses a “nearly equal” test to handle midpoint values:
function round(num, decimalPlaces = 0) {
if (num < 0)
return -round(-num, decimalPlaces);
var p = Math.pow(10, decimalPlaces);
var n = num * p;
var f = n - Math.floor(n);
var e = Number.EPSILON * n;
return (f >= .5 - e) ? Math.ceil(n) / p : Math.floor(n) / p;
}
console.log(round(0.5)); // 1
console.log(round(-0.5)); // -1
console.log(round(1.005, 2)); // 1.01
console.log(round(2.175, 2)); // 2.18
console.log(round(5.015, 2)); // 5.02
console.log(round(-1.005, 2)); // -1.01
console.log(round(-2.175, 2)); // -2.18
console.log(round(-5.015, 2)); // -5.02
3. Number.EPSILON
Using Number.EPSILON for correction offsets floating-point inaccuracies:
function round(num, decimalPlaces = 0) {
var p = Math.pow(10, decimalPlaces);
var n = (num * p) * (1 + Number.EPSILON);
return Math.round(n) / p;
}
console.log(round(0.5)); // 1
console.log(round(-0.5)); // -1
console.log(round(1.005, 2)); // 1.01
console.log(round(2.175, 2)); // 2.18
console.log(round(5.015, 2)); // 5.02
console.log(round(-1.005, 2)); // -1.01
console.log(round(-2.175, 2)); // -2.18
console.log(round(-5.015, 2)); // -5.02
4. Double Rounding
This method uses toPrecision()
to strip off round-off errors:
function round(num, decimalPlaces = 0) {
if (num < 0)
return -round(-num, decimalPlaces);
var p = Math.pow(10, decimalPlaces);
var n = (num * p).toPrecision(15);
return Math.round(n) / p;
}
console.log(round(0.5)); // 1
console.log(round(-0.5)); // -1
console.log(round(1.005, 2)); // 1.01
console.log(round(2.175, 2)); // 2.18
console.log(round(5.015, 2)); // 5.02
console.log(round(-1.005, 2)); // -1.01
console.log(round(-2.175, 2)); // -2.18
console.log(round(-5.015, 2)); // -5.02
5. Using decimal.js
Library
The decimal.js
library provides arbitrary-precision decimal arithmetic. For this, you need to import the file or the CDN: https://cdnjs.cloudflare.com/ajax/libs/decimal.js/10.2.1/decimal.js.
function round(num, decimalPlaces = 0) {
return new Decimal(num).toDecimalPlaces(decimalPlaces).toNumber();
}
console.log(round(0.5)); // 1
console.log(round(-0.5)); // -1
console.log(round(1.005, 2)); // 1.01
console.log(round(2.175, 2)); // 2.18
console.log(round(5.015, 2)); // 5.02
console.log(round(-1.005, 2)); // -1.01
console.log(round(-2.175, 2)); // -2.18
console.log(round(-5.015, 2)); // -5.02
Choosing the right method for rounding decimal numbers in JavaScript depends on the specific requirements and edge cases you need to handle. The improved methods address the inconsistencies and precision issues present in the naive approach, ensuring more accurate and reliable results.