按位运算符

专业人员经常使用按位运算符,通常用于提高与内存相关的性能。 它们是什么?何时使用它们?它们如何影响性能? 请继续关注所有其他答案!

这个话题使我很久了。 我看到了。 我听说了 我什至在没有完全理解它的情况下使用了它(至少在一开始)。 对于新手来说肯定会造成混乱(哎呀,当我已有10年的工作经验时,这对我来说是令人困惑的)。

我相信,如果我们对所学的概念知之甚少,我们只会对它们感到困惑。 因此,以消除混乱的名义,这是我试图有效地解释只有明智的人才能看到的一点

本文假定您知道什么是二进制数以及如何读取它们。 如果没有,您可能需要先阅读此内容,然后再继续。

假设您有一个应用程序(继续……我将等待),其中包含几个声明应用程序状态的布尔标志。 例如,这是其中一些假设标志及其含义的列表:

  1. 菜单打开 :我应该显示侧面菜单吗?
  2. 关注列表 :我应该突出显示列表组件吗?
  3. 请求进行中 :我应该显示进度圈吗?
  4. 进程X正在运行 :我应该显示进程X正在运行的迹象吗?

让我们进一步想象这些标志的当前单个状态如下:

  1. 0(假)
  2. 0(假)
  3. 1(真)
  4. 0(假)

因此,您可以按以下方式表示应用程序的状态:0010(参见图片) 下面):

这些0和1是我们的位。 每个位都是二进制的 ,这意味着每个位都有两个状态:1和0。

二进制序列 (0010)可以转换为十进制(我们人类看数字的直观方式(即1、2、3、4等))。 在JavaScript中,我们可以轻松地在两种表示形式之间进行转换。

从二进制到十进制:

parseInt(“0010”, 2); // results in “2”

从十进制到二进制:

const x = 2; x.toString(2); // results in “10”

这意味着每个二进制序列(或应用程序的每个二进制状态序列)都可以表示为单个整数!

那个怎么样? 您能想到这可能会对您的应用产生什么影响吗?

只是在说’…

您是否注意到,当我将0010转换为二进制时,结果是2,但是当我将2转换回二进制时,结果只有10? 发生这种情况是因为前导零无意义; 它们不添加任何信息,因此不需要。 原因如下:

000000000000000000000000010 = 10

到此结束本文的哲学部分。

您可能已经听说过该短语(或完整版本,如“ 32/64位带符号整数”)。 按位运算符使用32位带符号整数。 它们实际上将您提供作为输入的整数(稍后会详细介绍)转换为32位带符号整数。 让我们讨论什么是有符号整数,以有符号32位整数开头:

32位表示该数字由32位表示。

00000000000000000000000001100000 // 96

如果最左边的位表示数字的符号(即96对-96),则最左边的位称为符号位

这种32位带符号二进制格式称为二进制补码格式。 在此格式中,数字的负数对应项是数字中所有位(一个补码)加1的反数。 因此,请注意上面的96的32位表示形式,分两步来计算-96:

11111111111111111111111110011111 // -97->补码

+1

11111111111111111111111111100000 // // -96->二进制补码

使用二进制补码的原因不在本文的讨论范围之内,但在此进行解释。

逐位移位运算符正是其名称所隐含的含义–它们将位向左或向右移位。

从右边添加零。 这意味着该数字在每次移位时都会加倍,直到达到32位边界。 然后,我们开始使用有关符号位的知识。

让我们来看一个例子。

1 << 0 =“ 1” = 1

1 << 1 =“ 10” = 2

1 << 2 =“ 100” = 4

这是一个示例,展示了此概念的实际作用:

数字5由三个位表示: 101 。 回顾符号位规则:如果我们的符号位为0,则我们的数字为正。 如果为1,则我们的数字为负。 回想一下,可以这样写五个:

00000000000000000000000000000101

如果选择这样做,则我们的有符号(最左侧)位为零。

如果将此数字向左移动27位(5 << 27),则101的右边将添加27个零,将十进制值与每个零加倍。 由于数字以三位开头,因此在右边加27个零意味着我们现在有30位,包括和在101的右边。

01010000000000000000000000000000

这仍然使我们保持乐观,因为我们最左边的位仍然为0。

左移五位以获得28位(5 << 28),总共向右移31位。 仍然是积极的。

但是,如果我们将左移五位29位(5 << 29),则将达到32位,最左边的位将为1。 最后 ,我们的数为负!

我已经建立了这个简单的工具。 使用它,您可以输入一个数字并查看其左移值,最大不超过32个移位。 注意,数字越大,负值越早;反之,负值越大。 这是因为,一旦将二进制数中的任何1推到最左边的(第32位)位,它就会变成带符号的位并将数字的符号翻转为负数。

还是很困惑? 您可以在此处使用在线工具进行更多操作。

我们有两种右移方式:零填充( >>> )和符号保留( >> )。

零填充与左移功能相同,只不过它从左侧添加零(向右推动)。 如果我们的数字为负,则可能导致符号更改(因为它将更改符号位)。 您可以按以下方式使用它:

5000 >>> 3 // 625
-5000 >>> 3 // 536870287

保留符号会添加最左侧位的副本,因此保留了符号位。 您可以像这样使用它:

5000 >> 3 // 625
-5000 >> 3 //-625

您可以使用此工具查看它的运行情况。

现在我们知道什么是位以及如何操作它们,接下来我们可以继续进行按位逻辑运算符。 有四个按位逻辑运算符:

1.按位与(&)

这是按位与的示例:

5&13 //输出为5

该算法很好地表示了幕后发生的事情。

哈啦!

2.按位或(|)

按位OR运算符(|)与AND的作用相同,不同之处在于,只要至少一个相对位为1,它就会返回true。这是一个示例操作:

5 | 13 //输出为13

这是一个算法!

我为什么这么宠你?

3.按位XOR(^)

每当一对中只有一个位为1时,XOR(^)返回1,而当位相同时为0。 因此0/0返回0,1 / 1返回0,但是1/0和0/1返回1。它的用法如下:

5 ^ 13 //输出为8

实施XOR是您的功课。 它是相同的算法,但验证方式不同。

您可以通过浏览器的控制台验证结果(使用parseInt和toString(2)方法验证您的答案)。 您也可以使用像这样的二进制计算器进行调试。

4.不(〜)

NOT运算符(〜)只是翻转位。 因此,每1位变为0,反之亦然。 它仅接收一个操作数,如下所示:

〜16 //输出为-17

该算法易于实现。 用小数表示,如下所示:

-(x + 1)

现在您了解位运算符及其工作原理!

虽然我敢肯定您非常渴望尝试所学的知识,但在大多数情况下,最好是避免使用按位运算符以提高可读性。 但是,在对性能敏感的操作中(尤其是在游戏或其他渲染引擎(如Angular)中),按位运算符可能只是问题所在。

按位运算符广泛用于图形渲染(游戏吗?),但不仅限于此。 还有很多用例。 标志,压缩和加密是按位运算符的最常见用例。

在我即将发表的文章中,我将向您展示JavaScript中的实际用例及其性能含义。