We have come across a problem with Math.round() in JavaScript. The problem is that this function doesn't round correctly for negative numbers. For example :
1.5 ~= 2
0.5 ~= 1
-0.5 ~= 0 // Wrong
-1.5 ~= -1 // Wrong
And this is not correct according to arithmetic rounding. The correct numbers for -0.5 should be -1 and -1.5 should be -2.
Is there any standard way, to correctly round negative numbers in Javascript ?
You could save the sign and apply later, in ES5;
function round(v) {
return (v >= 0 || -1) * Math.round(Math.abs(v));
}
console.log(round(1.5)); // 2
console.log(round(0.5)); // 1
console.log(round(-1.5)); // -2
console.log(round(-0.5)); // -1
Apply Math.round
after converting to a positive number and finally roll back the sign. Where you can use Math.sign
method to get the sign from the number and Math.abs
to get the absolute of the number.
console.log(
Math.sign(num) * Math.round(Math.sign(num) * num),
// or
Math.sign(num) * Math.round(Math.abs(num))
)
var nums = [-0.5, 1.5, 3, 3.6, -4.8, -1.3];
nums.forEach(function(num) {
console.log(
Math.sign(num) * Math.round(Math.sign(num) * num),
Math.sign(num) * Math.round(Math.abs(num))
)
});
You could try using Math.ceil(num) to round num and then - 1 if num was negative, e.g.
if (num < 0) {
num = Math.ceil(num) - 1;
} else {
num = Math.ceil(num);
}
var r = (Math.random() * 200) - 100;
How about purely evaluating the result without using the math library? eg, by using a ternary operator, you can elegantly check for negative numbers and then floor after "rounding":
var n = r + (r < 0 ? -0.5 : 0.5) | 0;
The | 0
is just a silly trick in js that "overloads" the binary operator (you could use any binary operator) in order to truncate the number.
Note that this is not flooring (like Math.floor
), since Math.floor(-3.2)
, for example, will actually yield -4
.
One could even do something similar to @Balan's answer (I like that one and the one below, but I feel like this or the ternary operator will just be a touch faster--I am probably wrong, though, because the Math
libraries have been proven to be very fast):
var n = (r + Math.sign(r) / 2) | 0;
probably the fastest, most elegant way:
var n = Math.floor(r + 0.5);
example:
var body = document.getElementById("myTable").children[1];
var i, iMax = 100, r, tr, td;
for (i = 0; i < iMax; i++) {
r = Math.random() * 200 - 100;
tr = document.createElement("tr");
td = document.createElement("td");
td.innerHTML = r;
tr.appendChild(td);
td = document.createElement("td");
td.innerHTML = (r + Math.sign(r) / 2) | 0;
tr.appendChild(td);
body.appendChild(tr);
}
#myTable {
min-width: 250px;
}
<table id="myTable">
<thead>
<tr>
<th>float</th>
<th>round</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
Rounding with precision.
Rounds to Int by default or, if second argument is provided, to n digits after decimal point.
+ '1' fixes incorrect rounding for .0X5 numbers.
function round(num, digits=0) {
if (!(num % 1)) return num
return +Number(num + '1').toFixed(digits)
}