Swift 按位和移位运算符
在本教程中,您将学习 Swift 中的不同位操作。它们用于表达式中的位级计算。
位用来表示二进制数字。一个二进制数字可以有两个可能的值0或1。作为一个初级程序员,您不必在位级别使用操作。
使用原始数据类型,例如:integer, float, boolean, string等就足够了。在处理低级编程时,您可能需要在位级工作。
除了基本运算符外,Swift 还提供了一组丰富的操作符来操作位。这些运算符类似于逻辑运算符,只是它们处理数据(位)的二进制表示。
按位运算符是用于更改操作数的各个位的运算符。 操作数是在其中执行运算的变量或常量。
以下列出了swift中可用的所有位运算符:
1.按位非运算符
它由波浪符 ~ 表示,并可以应用于单个操作数。 这会将所有位反转。 即将1更改为0,将0更改为1。
如果x是一个保存二进制值(即0或1)的变量/常量,则x变量的按位非运算可以表示在下表中:
x | ~x |
---|---|
0 | 1 |
1 | 0 |
示例1:无符号整数的按位非运算符
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:以位为单位的按位非运算符
let initialBits: UInt8 = 0b11111111 let invertedBits = ~initialBits print(invertedBits)
当您运行上述程序时,输出将是:
0
initialBits包含二进制值11111111,它对应于十进制255。 为了用二进制表示数字,我们在文字中以0b作为前缀。 如果没有0b作为前缀,它将把它当作普通整数对待,并且会出现溢出错误(UInt8只能存储0到255之间的数字)。
由于我们使用了按位非运算符,因此将所有1都更改为0。因此,常量reverseBits包含00000000,这等效于UInt8中的0。
示例3:有符号整数的按位非运算符
let initalNumber:Int = 1 let invertedNumber = ~initalNumber print(invertedNumber)
当您运行上述程序时,输出将是:
-2
在上面的程序中,十进制的1可以二进制表示为00000001。 按位非运算符将更改变量或常量的所有位,将位0更改为1,将1更改为0。因此,反转数字包含位11111110。这应在屏幕中输出254。 而是返回-2。 奇怪吧? 让我们在下面看看这是如何发生的。
let initalNumber: Int = 1是一个有符号 Int,可以同时包含正整数和负整数。这就是为什么当我们对有符号整数应用非运算符时,返回的二进制数也可能表示负数。
编译器如何将 -2 解释 为11111110 二进制形式?
编译器使用二进制补码表示整数。 要获得整数的二进制补码负号,您应该首先以二进制形式写出数字,然后将数字取反,然后在结果中加一个。
求-2的补码的步骤:
以二进制形式写2: 00000010
反转数字。0变为1,而1变为0:11111101
加1: 11111110
这就是编译器将二进制数1111110解释为十进制中的-2的方式。 但是,编译器有一个我们没有注意到的小问题。 它还推断 invertedNumber 的类型为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。
如果x和y是变量/常量,保存二进制值,即0或1。x和y上的位与运算可表示为下表:
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 组合了两个操作数xBits和yBits的位。 如果这两个位都是1,则返回1,否则返回0。
String(value , radix: )初始值设定项用于表示不同数制中的数字。 如果我们提供基数值2。它将数字转换为二进制数系统。 同样,我们可以用16表示十六进制,用10表示十进制。
该语句print("Binary:",String(result, radix: 2))在屏幕上输出 Binary:10000011。10000011等于十进制的131,语句print(result)在控制台中输出131。
3.按位或运算符
它由 |表示,并且可以应用于两个操作数。如果按位或运算符的一个或多个输入为1,则将两个位相比较并生成结果1,否则为0。
如果x和y是保持二进制值(即0或1)的变量/常数,则x和y的按位或运算可以表示为下表:
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 语句结合了两个常量 xBits 和 yBits 的位。如果任何位都是1,则返回1,否则返回0。
该语句 print("Binary:",String(result, radix: 2)) 在屏幕上输出Binary:11111111。由于11111111与255十进制等效,因此print(result)语句在屏幕上输出255。
4.按位异或运算符
它由^表示,可以应用于两个操作数。异或运算符比较两个位,如果只有一个输入是1,则生成结果1,否则返回0。
如果x和y是变量/常量,保存二进制值,即0或1。x和y上的位异或运算可表示为下表:
x | y | x ^ y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 1 | 0 |
1 | 0 | 1 |
示例7:按位异或运算
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 语句结合了两个常量 xBits 和 yBits 的位。如果其中一个位正好是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。这些数字向左移动一个位置,右侧的最后一个数字填充零。
您还可以看到从左侧“末端”移位的数字丢失。 它不会再次从右侧绕回。 将其向左移位一位将从二进制中移除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。