上一章Swift教程请查看:swift三元条件运算符(三目运算符)
在本教程中,你将了解Swift中不同的位操作,它们用于表达式中的位级计算。
位是用来表示二进制数字的,一个二进制数字可以有两个可能的值,0或1。作为一个初级程序员,你不必在位级别上处理操作。
处理原始数据类型,如:整数、浮点数、布尔值、字符串等就足够了,在处理底层编程时,你可能需要在位级别上工作。
除了基本操作符之外,Swift还提供了一组丰富的操作符来操作位,这些操作符与逻辑操作符类似,只是它们处理的是数据的二进制表示(位)。
按位运算符是用来改变操作数的个别位的运算符,操作数是执行操作的变量或常量。
swift提供的所有位操作符如下:
1. 按位取反或非运算符
它由波浪~符号表示,可以应用于单个操作数,这是所有位的倒数或相反数,也就是从1到0,从0到1。
如果x是一个包含二进制值i的变量/常数,如0或1,对x变量的按位取反操作如下表所示:
NOT非运算符
x | ~x |
0 | 1 |
1 | 0 |
例1:无符号整数的按位非运算符
let initalNumber:UInt8 = 1
let invertedNumber = ~initalNumber
print(invertedNumber)
在上面的程序中,语句let
initalNumber:UInt8 = 1的类型是大小为8位的无符号整型,因此,1可以用二进制表示为00000001。
按位非运算符改变了一个变量或常数的所有位,0位变成了1,1变成了0。所以invertedNumber包含了11111110位。把它转换成小数后,它表示为254。因此,语句print(invertedNumber)在屏幕中输出254。
你也可以在多个位上直接执行按位运算符:
例2:按位非/取反操作符
let initialBits: UInt8 = 0b11111111
let invertedBits = ~initialBits
print(invertedBits)
initialBits包含二进制值11111111,它对应于255的十进制数。为了表示二进制中的数字,我们在文字中以0b作为前缀。如果没有0b作为前缀,它将把它当作普通整数,你将得到一个溢出错误(UInt8只能存储0到255之间的数字)。
因为我们使用了按位不运算符,所以它把所有的1变成0,因此,常量invertedBits包含00000000,它在UInt8中等于0。
例3:带符号整数的按位非运算符
let initalNumber:Int = 1
let invertedNumber = ~initalNumber
print(invertedNumber)
在上面的程序中,十进制的1可以表示为二进制的00000001。按位不运算符改变了一个变量或常数的所有位,0位变成了1,1变成了0。所以,invertedNumber包含了11111110位,这应该在屏幕中输出254,而不是返回-2。很奇怪,对吧???让我们来探索一下这是如何发生的。
let
initalNumber:Int = 1是一个有符号的整数,可以同时保存正整数和负整数。这就是为什么当我们对一个带符号整数应用not运算符时,返回的二进制也可能表示一个负数。
编译器如何将-2解释为二进制的11111110 ?
编译器用2的补码来表示整数,要得到整数的补数负号,你应该先把这个数写成二进制的形式,然后把数字反过来,再把1加到结果上。
求2的-2补码的步骤:
- 把2写成二进制形式:00000010
- 按位取反,0变成1,1变成0:11111101
- 加1:11111110
这就是编译器将二进制数字1111110解释为-2的方式。但是,编译器做了一点小小的改变,我们没有注意到,它还将invertedNumber的类型推断为Int8类型。
为了理解这一点,让我们看看下面的例子:
print(Int8(bitPattern: 0b11111110))
print(0b11111110)
在上面的例子中,编译器只将带符号的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)
在上面的程序中,let
result = xBits & yBits语句组合了两个操作数xBits和yBits的位。它返回1它的两位都是1,否则它返回0。
初始化器用于表示不同数字系统中的数字,如果我们提供基数值2,它将数字转换成二进制数字系统。类似地,十六进制可以用16,十进制可以用10。
语句print(“Binary:”,String(result,基数: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)
在上面的程序中,let
result = xBits | yBits语句组合了两个常量xBits和yBits的位。如果任何一位是1,它返回1,否则返回0。
语句print(“Binary:”,String(result,基数:2))在屏幕上输出Binary: 11111111。由于11111111在小数点后等于255,因此语句print(result)在屏幕上输出255。
4. 按位异或运算符
它表示为^,可以应用于两个操作数,XOR操作符比较两个位,如果其中一个输入恰好为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:按位异或XOR操作
let xBits = 0b10000011
let yBits = 0b11111111
let result = xBits ^ yBits
print("Binary:", String(result, radix: 2))
print(result)
在上面的程序中,语句let
result = xBits ^ yBits组合了两个常量xBits和yBits。如果其中一位正好是1,它就返回1,否则返回0。
语句print(“Binary:”,String(result,基数:2))在屏幕上输出Binary: 1111100(相当于01111100)。由于1111100等于124(以小数表示),因此语句print(result)在屏幕上输出124。
5. 按位移位运算符
此操作符用于将数字中的所有位移动到某个位置的左侧或右侧,并可应用于单个操作数,它表示为<<或>>。
有两种移位操作符:
按位左移位运算符
- 表示为< <
- 它使位元被移动到左边,由<<后面的数字指定。
- 移位操作空出的位位置为零。
- 将整数的位向左移动一个位置将使其值加倍
例8:按位左移操作符
let someBits:UInt8 = 0b11000100
print(someBits << 1)
在上面的程序中,我们使用了左移位运算符,使用<< 1表示将位向左移动1,数字向左移动了一个位置,右边的最后一个数字是0。
你也可以看到从左边移出“末端”的数字丢失了,它不再从右边环绕,将它向左移动1位将1从二进制中移除,并向右添加0来填充移动后的值,其他的位也向左移动1位。
返回10001000,相当于UInt8中的136。因此,print(someBits
<< 1)语句在屏幕上输出136。
按位右移位运算符
- 指示为> >
- 它使位被>>后面的数字向右移位
- 对于无符号数字,移位操作空出的位位置是零填充的。
- 对于有符号的数字(也可以是负数),符号位用于填充空出的位位置。换句话说,如果数字是正数,就用0,如果数字是负数,就用1。
- 右移一个位置,值减半。
例9:无符号整数的按位右移运算符
let someBits: UInt8 = 4
print(someBits >> 1)
在上面的程序中,我们对一个无符号整数使用了右移位运算符。使用>> 1表示将位向右移动1。移位操作空出的位位置在无符号整数上始终为零。
因为,4在二进制中表示为00000100。向右移动一位,返回00000010,等于UInt8中的2。因此,在屏幕上打印(someBits
>> 1)语句输出2。
例10:带符号整数的按位右移运算符
let someBits:Int = -4
print(someBits >> 1)
在上面的程序中,我们对一个无符号整数使用了右移位运算符。与正数不同,负数使用>>,1被用来填补空缺,而不是0。
因为,-4在二进制中表示为11111100。将它向右移动一位并将1放置在空位置,返回11111110,这对于Int8类型来说相当于-2。因此,在屏幕上打印(someBits >> 1)语句输出-2。