跳到主要内容

Swift 位运算和位移运算符

提示
  1. 位运算符概念:Swift中的位运算符对整数的单个位级别执行操作,包括位与(&), 位或(|), 位异或(^), 位非(~), 左位移(<<)和右位移(>>)。
  2. 操作原理简述:位与(&)运算符只在两个操作数都为1时返回1,位或(|)运算符在至少一个操作数为1时返回1,位异或(^)运算符在一个操作数为1时返回1,位非(~)运算符反转位,左右位移(<<, >>)分别向左右移动位数。
  3. 特别说明:位非运算(~)的结果是 -(N + 1)(N为操作数),左右位移运算符分别移动位数,左移丢弃最左边位,右移根据符号填补最右边位。

位运算符在整数数据的单个位级别上执行操作。这些操作包括测试、设置或移动实际的位。例如,

a & b
a | b

在这个例子中,&| 是位运算符。

这是 Swift 中包含的各种位运算符的列表

| 运算符 | 名称 | 示例 | | ------ | -------------------------------------------------- | --------------------------------------------- | --- | --- | | & | 位与 | a & b | | | | 位或 | a | b | | ^ | 位异或 | a ^ b | | ~ | 位非 | ~ a | | << | 左位移 | a << b | | >> | 右位移 | a >> b |

位与运算符

位与运算符 & 仅当两个操作数都是 1 时返回 1。否则,它返回 0

ab 的位与操作可以在下表中表示:

aba & b
000
010
100
111

注意: 上表被称为位与运算符的“真值表”。

让我们看一下两个整数 1225 的位与运算:

12 = 00001100(二进制)

25 = 00011001(二进制)

// 12 和 25 的位与运算

00001100
& 00011001
_____________
00001000 = 8(十进制)

示例 1:位与运算符

var a = 12
var b = 25

var result = a & b
print (result) // 8

在上述示例中,我们声明了两个变量 ab。这里,注意这一行,

var result = a & b

这里,我们正在执行 ab 之间的位与运算。

位或运算符

位或运算符 | 如果至少一个操作数是 1,则返回 1。否则,返回 0

ab 的位或操作可以在下表中表示:

aba | b
000
011
101
111

让我们看一下两个整数 1225 的位或运算:

12 = 00001100(二进制)
25 = 00011001(二进制)

// 12 和 25 的位或运算
00001100
| 00011001
____________
00011101 = 29(十进制)

示例 2:位或运算符

var a = 12
var b = 25

var result = a | b
print(result) // 29

在这里,我们对1225执行了位运算。

位异或运算符

异或运算符 ^ 只有在一个操作数为1时才返回1。然而,如果两个操作数都是0,或者都是1,那么结果就是0

ab 进行位异或运算可以用下表表示:

aba ^ b
000
011
101
110

让我们看看两个整数1225的位异或运算:

12 = 00001100 (二进制)
25 = 00011001 (二进制)

1225 的位异或运算
00001100
^ 00011001
____________
00010101 = 21 (十进制)

示例 3:位异或运算符

var a = 12
var b = 25

var result = a ^ b
print(result) // 21

在这里,我们对1225执行了位异或运算。

位非运算符

运算符 ~ 会反转位(0变为11变为0)。

Swift 位非运算将 0 反转为 1,1 反转为 0

a 进行位运算可以用下表表示:

需要注意的是,任何整数N的位运算结果等于 -(N + 1)。例如,

考虑一个整数35。根据规则,35的位应该是 -(35 + 1) = -36。现在,让我们看看是否能得到正确的答案。

35 = 00100011 (二进制)

// 使用位非运算符
~ 00100011
________
11011100

在上述示例中,00100011的位非是11011100。在这里,如果我们将结果转换为十进制,我们得到220

然而,需要注意的是,我们不能直接将结果转换为十进制并获得期望的输出。这是因为二进制结果11011100也等同于**-36**。

要理解这一点,我们首先需要计算**-36的二进制输出。我们使用2的补码**来计算负整数的二进制。

2的补码

一个数N2的补码得到**-N**。它是通过反转位(0变为11变为0)然后加上1来计算的。例如,

36 = 00100100 (二进制)

1的补码 = 11011011

2的补码:
11011011
+ 1
________
11011100 **
**

在这里,我们可以看到 362 的补数(即 -36)是 11011100。这个值等同于我们在前一节中计算的 35 的位补数。

因此,我们可以说 35 的位补数等于 -36

示例 4:位非运算符

var  b = 12

var result = ~b

print(result) // -13

在上述示例中,我们对 12 执行了位非运算。

12 的位补数 = - (12 + 1) = -13
~12 = -13

这正是我们在输出中得到的结果。

左移运算符

左移运算符将所有位向左移动指定的位数。它由 << 表示。

使用左移将所有位向左移动 1 位。

正如我们从上图中可以看到的,

  • 我们有一个 4 位数字。当我们对它执行 1 位 左移操作时,每个位都向左移动 1 位
  • 结果,最左边的位被舍弃,而最右边的位则变为空。这个空位被 0 替代。

示例 5:左移运算符

var a = 3

var result = a << 2

print(result) // 12

在上述示例中,我们创建了一个值为 3 的变量 a。注意这个语句

var result = a << 2

这里,我们正在对 a 执行 2 位 左移操作。

右移运算符

右移运算符将所有位向右移动指定的位数。它由 >> 表示。

位右移将所有位向右移动特定位数

正如我们从上图中可以看到的,

  • 我们有一个 4 位数字。当我们对它执行 1 位 右移操作时,每个位都向右移动 1 位
  • 结果,最右边的位被舍弃,而最左边的位则变为空。对于无符号数,这个空位被 0 填补。
  • 对于有符号数,符号位(0 表示正数1 表示负数)用于填充空位。

注意: 有符号整数表示正负整数,而无符号整数仅表示正整数。

示例 5:右移运算符

var a = 4

var result = a >> 2
print(result) // 1

a = -4

result = a >> 2
print(result) // -1

在上述示例中,我们对值 4-4 执行了 2 位 右移操作。

正如您所看到的,4-4 的结果不同。这是因为 4 是无符号整数,所以空位被 0 填补,而 -4 是负的有符号数,所以空位被 1 填补。