开发者

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
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜