Efficient way to round n to a multiple of m
Here's what I currently have:
function getNearestMultipleOf(n, m) {
return Math.round(n/m) * m;
}
console.log(getNearestMultipleOf(37,18)); //36
A friend told me Math.round is expensive and a more eff开发者_运维知识库icient way is to use modulo to check if n has to be rounded up or down and use either Math.ceil
or floor
.
How would you do this?
Why not use modular operator and simple substraction ? http://jsfiddle.net/LCDy6/1/
function getNearestMultipleOf(n, m) {
lessOne = n-(n%m);
moreOne = lessOne + m;
if((n-lessOne) < (moreOne - n))
return lessOne;
else
return moreOne;
}
alert(getNearestMultipleOf(38,3));
Here's a simple approach based on what you mention:
function getNearestMultipleOf(n, m) {
if (n % m >= m / 2) {
return Math.ceil(n/m) * m;
}
else {
return Math.floor(n/m) * m;
}
}
pseudocode:
let r = n modulo m;
let q = Math.Floor( n / m ); //div
if(r < m / 2.0)
answer = q*m;
else
answer = (q+1)*m;
I think this is what you're looking for, but you should probably verify the claim the Math.round is expensive before looking for an alternative.
function getNearestMultipleOf(n,m) {
return Math[n%m < m/2 ? 'floor' : 'ceil'](n/m) * m;
}
Tried a bunch of ways:
<script>
// Math
var floor = Math.floor;
var time1 = +new Date();
var n = 586;
var m = 18;
// Math.round
for (var h=1.01, i = 5000000; i--;) {
Math.round(n/m) * m;
}
console.log("Math.round:" + (+new Date() - time1));
// Math.ceil/floor
time1 = +new Date();
for (var h=1.01, i = 5000000; i--;) {
if (n%m < m/2) {
Math.floor(n/m) * m;
} else {
Math.ceil(n/m) * m;
}
}
console.log("Math.floor/ceil:" + (+new Date() - time1));
// Shorter Math.ceil/floor
time1 = +new Date();
for (var h=1.01, i = 5000000; i--;) {
Math[n%m < m/2 ? 'floor' : 'ceil'](n/m) * m;
}
console.log("Shorter Math.ceil/floor:" + (+new Date() - time1));
// Bitwise1
time1 = +new Date();
for (var h=1.01, i = 5000000; i--;) {
if (n%m < m/2) {
~~(n/m) * m;
} else {
~~(n/m + 1) * m;
}
}
console.log("Bitwise1:" + (+new Date() - time1));
// Bitwise2
time1 = +new Date();
for (var h=1.01, i = 5000000; i--;) {
~~(n/m + 0.5) * m;
}
console.log("Bitwise2:" + (+new Date() - time1));
// lessOne/moreOne
time1 = +new Date();
for (var h=1.01, i = 5000000; i--;) {
lessOne = n-(n%m);
moreOne = lessOne + m;
if((n-lessOne) < (moreOne - n)) {
//lessOne;
} else {
//moreOne;
}
}
console.log("lessOne/moreOne:" + (+new Date() - time1));
</script>
Result:
Math.round:188
Math.floor/ceil:215
Shorter Math.ceil/floor:381
Bitwise1:171
Bitwise2:135
lessOne/moreOne:120
精彩评论