我正在寻找一种在JavaScript中生成宽度从0到32位不等的位掩码的方法.这必须适用于从0到32的所有宽度,以便:
> bitmask(0)应该以二进制(十进制0)返回0;
> bitmask(2)应该以二进制(十进制3)返回11;
> bitmask(5)应该以二进制(十进制31)返回11111;
> bitmask(32)应该以二进制(十进制4294967295 [uint32]或-1 [int32])返回11111111111111111111111111111111.
表达式(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中,按位运算符可将操作数视为32位整数.从the MDN Documentation开始:
The operands of all bitwise operators are converted to signed 32-bit integers in two’s complement format.
这意味着31位用于表示实际数字,一位(最左侧)用于表示符号.因此,尝试执行x<< 31将导致溢出并产生错误的结果. 解决方法 您应该考虑使用其他方法,例如Math.pow(),以获得更长的位掩码(和更高的值).这是一个例子:
function bitmask(width) {
return Math.pow(2, width) - 1;
}
现在,假设JavaScript使用IEEE Standard 754浮点表示形式,此功能也将受到限制:它仅适用于短于54位的位掩码.例如,bitmask(54)产生一个比正确的整数高一个单位的整数,bitmask(55)产生一个比正确的整数高三个单位的整数,依此类推,误差随位掩码的宽度而增大.
另外,请注意,即使此函数产生的掩码长度大于31位,但由于上述原因,这些掩码仍不能与按位运算符一起使用.