📜  Swift按位和移位运算符

📅  最后修改于: 2020-10-09 15:40:50             🧑  作者: Mango

在本教程中,您将学习Swift中的不同按位运算。这些用于表达式中的位级别计算。

一位用来表示二进制数字。二进制数可以有两个可能的值0或1。作为初学者级程序员,您不必在位级别进行操作。

使用原始数据类型,例如:整数,浮点数,布尔值, 字符串等就足够了。在处理低级编程时,您可能需要在位级工作。

除了基本运算符 符外,Swift还提供了丰富的运算符集来操作位。这些运算符与逻辑运算符 符相似,不同之处在于它们以数据(位)的二进制表示形式工作。

按位运算符 运算符是用于更改操作数的各个位的运算符。操作数是完成操作的变量或常量。

下面列出了所有迅速可用的按位运算运算符 :


1.按位NOT运算符

它由代字号~符号表示,可以应用于单个操作数。这会将所有位反转。即将1更改为0,将0更改为1。

如果x是一个保存二进制值(即0或1)的变量/常数,则x变量的按位非运算可以表示在下表中:

NOT
x ~x
0 1
1 0

示例1:无符号整数的按位NOT 运算符

let initalNumber:UInt8 = 1 
let invertedNumber = ~initalNumber 
print(invertedNumber)

当您运行上述程序时,输出将是:

254

在上面的程序中,语句let initalNumber:UInt8 = 1的类型为Unsigned int,大小为8位。因此,十进制的1可以二进制表示为00000001

按位非运算符更改变量或常量的所有位,位0会更改为1,而1会更改为0。因此反相数字包含位11111110 。将其转换为十进制后,它表示为254。因此,语句print(invertedNumber)在屏幕上输出254。

您还可以直接在位中执行按位运算运算符 ,如下所示:


示例2:以位为单位的按位NOT 运算符

let initialBits: UInt8 = 0b11111111
let invertedBits = ~initialBits  
print(invertedBits)

当您运行上述程序时,输出将是:

0

initialBits包含二进制值11111111 ,它对应于十进制255。为了用二进制表示数字,我们在字面量中以0b作为前缀。如果没有0b作为前缀,它将把它当作普通整数对待,并且会出现溢出错误(UInt8只能存储0到255之间的数字)。

因为,我们已经使用了按位没有运算符,它改变了所有的1比0。因此,不断invertedBits包含00000000 ,相当于0 UInt8


示例3:有符号整数的按位NOT 运算符

let initalNumber:Int = 1 
let invertedNumber = ~initalNumber 
print(invertedNumber)

当您运行上述程序时,输出将是:

-2

在上面的程序中,十进制的1可以二进制表示为00000001 。按位非运算符更改变量或常量的所有位,位0会更改为1,而1会更改为0。因此, 反转数字包含位11111110 。这应该在屏幕中输出254。而是返回-2。奇怪吧?让我们在下面探讨这是如何发生的。

let initalNumber:Int = 1是一个可以容纳正整数和负整数的有符号整数。这就是为什么当我们不对有符号整数应用运算符时,返回的二进制也可能表示负数的原因。

编译器如何将-2解释为二进制形式的11111110

编译器使用二进制补码表示整数。要获得整数的二进制补码负号,您应该首先以二进制形式写出数字,然后将数字取反,然后在结果中加一个。

找出-2的2的补数的步骤

  1. 以二进制形式写2: 00000010
  2. 反转数字。 0变成1且1变成0: 11111101
  3. 加1: 11111110

这就是编译器将二进制数1111110解释为十进制-2的方式。但是,编译器有些许变化,我们没有注意到。它还将反相 Int8类型推断为Int8类型。


为了理解这一点,让我们看下面的例子:

print(Int8(bitPattern: 0b11111110))
print(0b11111110)

当您运行上述程序时,输出将是:

-2
254

在上面的示例中,编译器仅对带符号的8位整数将二进制数处理为十进制的-2。因此,语句print(Int8(bitPattern: 0b11111110))在屏幕上输出-2。

但是对于大小为32/64位并且可以容纳较大值的普通整数类型,它将值解释为254 。因此,语句print(0b11111110)在屏幕上输出254


2.按位与运算符

它由&表示,可以应用于两个操作数。 AND 运算符比较两个位,如果两个位均为1,则返回1,否则返回0。

如果xy是可变/恒定保持x上即0或1的位与二进制值运算和y可以在下面表来表示:

AND
x y x & y
0 0 0
0 1 0
1 1 1
1 0 0

示例5:按位与运算

let xBits = 0b10000011
let yBits = 0b11111111
let result = xBits & yBits
print("Binary:",String(result, radix: 2))
print(result)

当您运行上述程序时,输出将是:

Binary: 10000011
131

在上面的程序中,语句let result = xBits & yBits组合了两个操作数xBitsyBits的位 。如果两个位均为1,则返回1,否则返回0。

String(value , radix: )初始值设定项用于表示不同数字系统中的数字。如果我们提供基数值2。它将数字转换为二进制数系统。同样,十六进制可以使用16,十进制可以使用10。

语句print("Binary:",String(result, radix: 2))在屏幕上输出Binary:1000001110000011等于十进制的131,语句print(result)在控制台中输出131。


3.按位或运算符

它表示为|并可以应用于两个操作数。如果按位或运算符的一个或多个输入为1,则将两个位相比较并生成结果1,否则为0。

如果xy是可变/恒定保持x上即0或1。按位或二进制值运算和y可以在下面表来表示:

OR
x y x | y
0 0 0
0 1 1
1 1 1
1 0 1

示例6:按位或运算

let xBits = 0b10000011
let yBits = 0b11111111
let result = xBits | yBits
print("Binary:", String(result, radix: 2))
print(result)

当您运行上述程序时,输出将是:

Binary: 11111111
255

在上面的程序中,语句let result = xBits | yBits组合了两个常量xBitsyBits的位 。如果任何位为1,则返回1,否则返回0。

语句print("Binary:",String(result, radix: 2))在屏幕上输出Binary:11111111 。由于11111111等于十进制255 ,因此语句print(result)在屏幕上输出255


4.按位XOR 运算符

它用^表示,可以应用于两个操作数。如果XOR 运算符的输入之一恰好是1,则XOR 运算符将比较两个位并生成结果1,否则返回0。

如果xyx上持有即0或1。按位XOR运算的二进制值和y可以在下面表来表示变量/常数:

XOR
x y x ^ y
0 0 0
0 1 1
1 1 0
1 0 1

示例7:按位XOR操作

let xBits = 0b10000011
let yBits = 0b11111111
let result = xBits ^ yBits
print("Binary:", String(result, radix: 2))
print(result)

当您运行上述程序时,输出将是:

Binary: 1111100
124

在上面的程序中,语句let result = xBits ^ yBits组合了两个常量xBitsyBits的位 。如果确切的位之一是1,则返回1,否则返回0。

语句print("Binary:",String(result, radix: 2)) )在屏幕上输出Binary:1111100 (相当于01111100)。由于1111100等于十进制的124 ,因此语句print(result)在屏幕上输出124


5.按位移位运算符

该运算符用于将数字中的所有位向左或向右移动一定数量的位置,并且可以应用于单个操作数。它表示为<<>>

移位运算符有两种:


按位左移运算符

  • 表示为<<
  • 它将导致这些位向左移动,后跟数字,后跟<<
  • 移位操作已腾空的位位置为零。
  • 将整数的位向左移一位将其值加倍

示例8:按位左移运算符
let someBits:UInt8 = 0b11000100
print(someBits << 1) 

当您运行上述程序时,输出将是:

136

在上面的程序中,我们使用了左移运算符。使用<<表示将位左移1。这些数字向左移动一个位置,右侧的最后一个数字填充零。

您还可以看到从左侧“结束”移位的数字丢失了。它不会从右侧再次缠绕。将其向左移一位将二进制文件中的1删除,向右添加0以填充移位后的值,其余的其他位则向左移1。

这将返回10001000 ,相当于UInt8 136 。因此, print(someBits << 1)语句在屏幕中输出136


按位右移运算符

  • 表示为>>
  • 这会使位向右移动数字,后跟>>
  • 对于无符号数字,移位操作已腾空的位位置为零。
  • 对于带符号的数字(也可以为负的数字),符号位用于填充腾出的位位置。换句话说,如果数字为正,则使用0;如果数字为负,则使用1。
  • 向右移动一个位置将其值减半。

示例9:无符号整数的按位右移运算符
let someBits: UInt8 = 4     
print(someBits >> 1)

当您运行上述程序时,输出将是:

2

在上面的程序中,我们对无符号整数使用了右移运算符 。使用>> 1表示将位右移1。通过移位操作腾出的位位置始终以无符号整数填充零。

由于4以二进制形式表示为00000100 。向右移动一位,返回00000010 ,它等效于UInt8 2 。因此, print(someBits >> 1)语句在屏幕上输出2。


示例10:有符号整数的按位右移运算符
let someBits:Int = -4     
print(someBits >> 1)

当您运行上述程序时,输出将是:

-2

在上面的程序中,我们对无符号整数使用了右移运算符 。与正数不同,使用>>表示负数,使用1填充空位,而不是0。

由于-4以二进制表示为11111100 。将其向右移一位并将1放置在空闲位置,将返回11111110 ,对于Int8类型,该值等于-2 。因此, print(someBits >> 1)语句在屏幕上输出-2。