最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

Javascript bitshift alternative to math.round - Stack Overflow

programmeradmin1浏览0评论
var1=anyInteger
var2=anyInteger

(Math.round(var1/var2)*var2)

What would be the syntax for JavaScripts bitshift alternative for the above?

Using integer not floating

Thank you

var1=anyInteger
var2=anyInteger

(Math.round(var1/var2)*var2)

What would be the syntax for JavaScripts bitshift alternative for the above?

Using integer not floating

Thank you

Share Improve this question edited Jul 13, 2010 at 2:23 Mark Elliot 77k23 gold badges144 silver badges162 bronze badges asked Jul 13, 2010 at 2:15 cubecube 1,8024 gold badges25 silver badges35 bronze badges 7
  • The pn and sn are simply variables for integers. Could just as well be (Math.round(2/4)*4). Thank you – cube Commented Jul 12, 2010 at 23:59
  • Are you sure you mean bit shifting? Bit shifting would double or half the value for each shift you do. If var2 were always a power of 2 then it would work, but if var2 was ever an odd number the logic to handle it would be more overhead than just dividing it. – Andir Commented Jul 13, 2010 at 2:20
  • read this several times and still don't understand your question .. please rephrase what you are trying to do – Scott Evernden Commented Jul 13, 2010 at 2:33
  • Ok, doesn't a bitwise shift of zero (>>0) always round down? so just trying to find a bitwise shift formula that can round up or down depending on the values of the var's. – cube Commented Jul 13, 2010 at 2:45
  • >>0 is a no-op .. what are you trying to do ? – Scott Evernden Commented Jul 13, 2010 at 2:57
 |  Show 2 more comments

5 Answers 5

Reset to default 10

[UPDATED] The quick answer:

var intResult = ((((var1 / var2) + 0.5) << 1) >> 1) * var2;

It's faster than the Math.round() method provided in the question and provides the exact same values.

Bit-shifting is between 10 and 20% faster from my tests. Below is some updated code that compares the two methods.

The code below has four parts: first, it creates 10,000 sets of two random integers; second, it does the round in the OP's question, stores the value for later comparison and logs the total time of execution; third, it does an equivalent bit-shift, stored the value for later comparison, and logs the execution time; fourth, it compares the Round and Bit-shift values to find any differences. It should report no anomalies.

Note that this should work for all positive, non-zero values. If the code encounters a zero for the denominator, it will raise and error, and I'm pretty sure that negative values will not bit-shift correctly, though I've not tested.

var arr1 = [],
    arr2 = [],
    arrFloorValues = [],
    arrShiftValues = [],
    intFloorTime = 0,
    intShiftTime = 0,
    mathround = Math.round, // @trinithis's excellent suggestion
    i;

// Step one: create random values to compare
for (i = 0; i < 100000; i++) {
    arr1.push(Math.round(Math.random() * 1000) + 1);
    arr2.push(Math.round(Math.random() * 1000) + 1);
}

// Step two: test speed of Math.round()
var intStartTime = new Date().getTime();
for (i = 0; i < arr1.length; i++) {
    arrFloorValues.push(mathround(arr1[i] / arr2[i]) * arr2[i]);
}
console.log("Math.floor(): " + (new Date().getTime() - intStartTime));

// Step three: test speed of bit shift
var intStartTime = new Date().getTime();
for (i = 0; i < arr1.length; i++) {
    arrShiftValues.push( ( ( ( (arr1[i] / arr2[i]) + 0.5) << 1 ) >> 1 ) * arr2[i]);

}
console.log("Shifting: " + (new Date().getTime() - intStartTime));

// Step four: confirm that Math.round() and bit-shift produce same values
intMaxAsserts = 100;
for (i = 0; i < arr1.length; i++) {
    if (arrShiftValues[i] !== arrFloorValues[i]) {
        console.log("failed on",arr1[i],arr2[i],arrFloorValues[i],arrShiftValues[i])
        if (intMaxAsserts-- < 0) break;
    }
}

you should be able to round any number by adding 0.5 then shifting off the decimals...

var anyNum = 3.14;
var rounded = (anyNum + 0.5) | 0;

so the original expression could be solved using this (instead of the slower Math.round)

((var1/var2 + 0.5)|0) * var2

Run the code snippet below to test different values...

function updateAnswer() {
  var A = document.getElementById('a').value;
  var B = document.getElementById('b').value;

  var h = "Math.round(A/B) * B = <b>" + (Math.round(A/B) * B) + "</b>";
  h += "<br/>";
  h += "((A/B + 0.5)|0) * B = <b>" + ((A/B + 0.5) | 0) * B +"</b>";
  
  document.getElementById('ans').innerHTML = h;
}
*{font-family:courier}
  A: <input id="a" value="42" />
  <br/>
  B: <input id="b" value="7" />
  <br/><br/>
  <button onclick="updateAnswer()">go</button>
  <hr/>
  <span id="ans"></span>

If var2 is a power of two (2^k) you may write

(var1>>k)<<k

but in the general case there is no straightforward solution.

You can do (var | 0) - that would truncate the number to an integer, but you'll always get the floor value. If you want to round it, you'll need an additional if statement, but in this case Math.round would be faster anyway.

Unfortunately, bit shifting operations usually only work with integers. Are your variables integers or floats?

发布评论

评论列表(0)

  1. 暂无评论