【问题标题】:Create variable width bitmasks (0-32 bits) in JavaScript在 JavaScript 中创建可变宽度位掩码(0-32 位)
【发布时间】:2016-09-23 11:59:47
【问题描述】:

我正在寻找一种在 JavaScript 中生成从 0 到 32 位不等宽度的位掩码的方法。这必须适用于从 0 到 32 的所有宽度,因此:

  • bitmask(0) 应该以二进制形式返回 0(十进制 0);
  • bitmask(2) 应该以二进制形式返回 11(十进制 3);
  • bitmask(5) 应该以二进制形式返回 11111(十进制 31);
  • bitmask(32) 应该以二进制形式返回 11111111111111111111111111111111(十进制 4294967295 [uint32] 或 -1 [int32])。

表达式 (1 << width) - 1 适用于从 0 到 30 的宽度。

是否有一个简单的表达式(最好没有 if/else 分支)可以为所有输入范围 (0-32) 完成此操作?

此测试代码说明了我当前的方法在 31 和 32 上是如何失败的:

function bitmask(width) {
  return (1 << width) - 1;
}

function test(width){
  var result = bitmask(width).toString(2);
  console.log(width, 
              result, 
              result.replace(/[^1]/g,'').length === width? 'Ok': 'Fail');
}

test(0);
test(1);
test(5);
test(17);
test(30);
test(31); // fails
test(32); // fails

【问题讨论】:

标签: javascript bit-manipulation bitmask


【解决方案1】:

问题

在 JavaScript 中,按位运算符将操作数视为 32 位整数。来自the MDN Documentation

所有位运算符的操作数都转换为二进制补码格式的有符号 32 位整数。

这意味着31位用于表示实际数字,一位(最左边)用于表示符号。所以尝试像x &lt;&lt; 31 这样的操作会导致溢出并产生错误的结果。

解决方法

您应该考虑使用不同的方法,例如Math.pow(),以获得更长的位掩码(和更高的值)。这是一个例子:

function bitmask(width) {
    return Math.pow(2, width) - 1;
}

现在,鉴于 JavaScript 使用 IEEE Standard 754 浮点表示,此函数也将存在限制:它仅适用于小于 54 位的位掩码。例如,bitmask(54) 产生一个比正确值高 1 个单位的整数,bitmask(55) 产生一个比正确值高 3 个单位的整数,依此类推,误差随着位掩码宽度的增加而增大。

另外,请注意,即使此函数可以生成超过 31 位的位掩码,由于上述原因,这些位掩码仍然不能与位运算符一起使用。

【讨论】:

  • 简单的表达,很好的答案。谢谢。
【解决方案2】:

使用Math.pow() 而不是位移。这将起作用,因为 Javascript 中的所有数字都是 64 位“双”精度 IEE754 浮点数。

function bitmask(width) {
  return Math.pow(2, width) - 1;
}

function test(width){
  var result = bitmask(width).toString(2);
  console.log(width, 
              result, 
              result.replace(/[^1]/g,'').length === width? 'Ok': 'Fail');
}

test(0);
test(1);
test(5);
test(17);
test(30);
test(31);
test(32);

【讨论】:

【解决方案3】:

鉴于表达式 -1 &gt;&gt;&gt; (32 - width) 适用于输入宽度 1-32,另一种可能的解决方案是表达式 width &amp;&amp; -1 &gt;&gt;&gt; 32 - width,它适用于所有输入范围。

虽然比公认的答案更难阅读,但这个表达式还有其他好处:

  1. 它避免了函数调用(对Math.pow
  2. 可以用更少的字符编写(代码打高尔夫球):
    • w&amp;&amp;-1&gt;&gt;&gt;32-w(12 个字符),对比
    • Math.pow(2,w)-1,(15 个字符)

演示代码:

function bitmask(width) {
  return width && -1 >>> 32 - width;
}

// demonstrate that it works

for(var i = 0; i <= 32; i++) {
  console.log(i, bitmask(i).toString(2));
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多