首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在JavaScript中,位移位可以用来隔离一个字节中的一个或多个位吗?

在JavaScript中,位移位可以用来隔离一个字节中的一个或多个位吗?
EN

Stack Overflow用户
提问于 2017-01-09 12:48:03
回答 3查看 428关注 0票数 3

在JavaScript代码中,字节的8位表示8个布尔“决策”(又名:标志),需要隔离每个给定位以转换为布尔变量。考虑一下我使用字符串解析的解决方案:

代码语言:javascript
复制
var bitParser = function (_nTestByte, _nBitOrdinal) {
  var bits = ("00000000" + _nTestByte.toString(2)).slice(-8); // convert to binary and zero-pad
  return bits[_nBitOrdinal] === "1";
};

console.log(bitParser(0b10100101, 2)); // ECMAScript 6+ prefix, returns true

它可以工作,并显示所需的结果。然而,我有一个假设,即一点移位技术比字符串操作更快。我倾向于相信这一点,但却渴望证明这一点。

问题是,我还没有产生这样一个正确工作的函数,更不用说我可以测试的东西了。我创建了以下逻辑计划,我认为这是正确的:

代码语言:javascript
复制
/*
  LOGIC PLAN
  ----------
  0) Remember: all bitwise operators return 32 bits even though we are using 8
  1) Left shift until the desired bit is the left-most (highest) position;
  2) Right shift (zero filling) 31 bits to eliminate all right bits
*/

登录计划的实现如下。由于位运算符的32位性质,我认为必须先移除整个左3字节(24位),然后才能到达正在处理的字节。然后,假设左边的第三个位(字符串序数2)是所需的位,我将移出另外两个位(序数0& 1),总共是26位左移位。

这应该会产生一个二进制数,其馀所有的位都是所需的,后面跟着31个不需要的零字节。向右移动这31位将产生一个二进制,其中31 (现在)引导零位,其计算值为所需位的值。当然,如果这是真的,我就不会写这个问题了,现在我会写吗?

代码语言:javascript
复制
// hardcoded, assuming the second "1" (ordinal 2) is the bit to be examined
console.log((0b10100101 << 26) >> 31); // instead of 1, returns -1

我觉得我真的很接近,但是错过了一些东西,或者把JavaScript推得太紧了(lol)。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-01-09 12:55:06

在JavaScript代码中,字节的8位表示8个布尔“决策”(又名:标志),需要隔离每个给定位以转换为布尔变量.

如果这是实际目标,那么位移法既没有必要也没有用处:只需使用按位的&和所需的位,这将为您提供0或设置了该位的数字。0是虚假的,有位设置的数字是真实的。您可以按原样使用,也可以通过!!flagBoolean(flag)强制使用布尔值。

下面是使用位掩蔽的bitParser函数:

代码语言:javascript
复制
var bitParser = function (_nTestByte, _nBitOrdinal) {
  return !!(_nTestByte & Math.pow(2, _nBitOrdinal));
};
console.log(bitParser(0b10100101, 2)); // true
console.log(bitParser(0b10100101, 1)); // false

当然,与其每次执行Math.pow,不如使用一个查找表:

代码语言:javascript
复制
var bits = [
  0b00000001,
  0b00000010,
  0b00000100,
  0b00001000,
  0b00010000,
  0b00100000,
  0b01000000,
  0b10000000
];
var bitParser = function (_nTestByte, _nBitOrdinal) {
  return !!(_nTestByte & bits[_nBitOrdinal]);
};
console.log(bitParser(0b10100101, 2)); // true
console.log(bitParser(0b10100101, 1)); // false

票数 2
EN

Stack Overflow用户

发布于 2017-01-09 14:28:56

是的,它可以,而且你所做的几乎是正确的。

整数表示为32位二进制数,最左边的位表示符号(如果数字为负数,则为1,如果数字为正,则为0 )。让我们来看看其中一些数字的表示:

代码语言:javascript
复制
//last 31 digits keeps increasing as the number decreases
// ...
-2 => 0b11111111111111111111111111111110
-1 => 0b11111111111111111111111111111111
 0 => 0b00000000000000000000000000000000
 1 => 0b00000000000000000000000000000001
 2 => 0b00000000000000000000000000000010
// ...
// last 31 digits keep increasing as the number increases

现在,您所拥有的(0b10100101 << 26)应该为您提供10010100000000000000000000000000,您希望它是一个很大的负数(因为最左边的是1)。然后,你就有了>> 31,你期望它能去掉所有的31位,然后留给你最左边的部分。

这应该有效,但不是发生了什么。为什么会这样呢?这是因为想出ECMAScript的人认为如果4 >> 1返回2-4 >> 1返回-2会更有意义。

代码语言:javascript
复制
4 >> 1 // returns 2 which is 0b00000000000000000000000000000010
0b0000000000000000000000000000000100 >> 1 // returns 2, same

-4 >> 1 // returns -2, which is 0b11111111111111111111111111111110

但是-4是0b11111111111111111111111111111100,为了您的目的,将其右移1会产生0b01111111111111111111111111111110 (大正数,因为左后位是0),这不是-2

为了克服这个问题,您可以使用另一个右移位操作符,它不关心符号:>>>-4 >>> 12147483646,这就是我们想要的。

所以console.log((0b10100101 << 26) >>> 31);给了你1,这就是你想要的。您还可以继续使用>>,并将任何负面结果视为选择1的结果。

票数 1
EN

Stack Overflow用户

发布于 2017-01-09 12:53:51

实现实际需要的最简单方法是使用简单的条件,而不是试图隔离位数。

代码语言:javascript
复制
    var bitParser = function (_nTestByte, _nBitOrdinal) {
      return (_nTestByte & _nBitOrdinal);
    };
    
    console.log(bitParser(6, 2) ? true : false); // true
    console.log(bitParser(6, 1) ? true : false); // false

我以一种看似复杂的方式修改了console.log()表达式。

这只是在这个步骤中真正显示逻辑结果,而我并没有选择在函数中使用!!,所以返回一个真正的/falsy值,而不是返回true\false

实际上,这种方法保持了所有最简单的可能,因为代码中的预期使用if (bitParser(...))会自动将结果转换为布尔值。

顺便说一句,不管_nTestByte大小多大(可能超过1字节),它都能工作。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/41548443

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档