文中整数都以Int8
为例,Int8
大小为1字节
,区间值为-128至127
8比特位 = 1符号位 + 7数值位
即二进制表示为:
多说几句:
符号位0
为正数
,1
为负数
。
127 = 26 + 25 + 24 + 23 + 22 + 21 + 20
-128 = - (27 - |0|)
二进制转十进制
正数的二进制转十进制不用多说了。
负数的二进制转十进制时符号位
是 1 表示负数,2n 减去数值位
十进制值的绝对值(n为位数)。
再举个栗子:
- (27 - |26 + 25 + 24 + 22 + 20|) = -10
十进制转二进制
正数的十进制转二进制不用多说了。
负数的十进制转二进制是正数的补码。
位与运算符(&)
两个数进行位与运算
,每一个比特位依次计算,只有数值位对应的两个二进制值都是 1 的时候才是 1。
位或运算符(|)
与&
同理,|
是只要数值位对应的两个二进制值任意一个是 1 的时候就是 1。
位异或运算符(^)
与&
同理,^
是只有数值位对应的两个二进制值不相等时是 1。
位取反运算符(~)
一个数进行位取反运算
,每一个比特位依次取反,即1
为0
。
可以知道
~
就是原码转反码的过程。
位左移运算符(<<)
位左移运算
简单来说是一个数所有数值位的二进制值向左移动确定位数。
-
无符号整数
例如:10<<5
-
有符号整数
例如:-10<<5
- 所有比特位按指定的位数进行左移。
- 空白位用
0
补充。 - 超出整形存储边界都舍弃,例如上图中
Int8
类型的10
,位左运算
后置灰部分
应舍弃,值为64
。若是Int64
类型的10
,位左运算
后置灰部分
不应舍弃,值为320
。 - 可以看出一个数
位左移 1
后在整型存储范围内(没有舍弃部分)相当于将这个数x2
。
例如:
var i: Int = 20
print(I<<2)
运行结果:80
即:20*2*2 = 80
位右移运算符(>>)
同理,位左移运算
简单来说是一个数所有数值位的二进制值向右移动确定位数。
-
无符号整数
例如:10>>5
-
有符号整数
例如:-10>>5
- 所有比特位按指定的位数进行右移。
-
无符号整数
空白位用0
补充,有符号整数
空白位用符号位
数值补充。 - 超出整形存储边界都舍弃。
- 可以看出一个数
位左移 1
后在整型存储范围内(没有舍弃部分)相当于将这个数/2
,若位左移
导致结果<1
则无符号整数
结果为0
,有符号整数
中的负数
结果为-1
。
例如:
var i: Int =20
print(i<<2)
运行结果:5
即:20/2/2 = 5
几个常见的位运算符操作总结
- 两个数 ^ 得到的结果,再 ^ 其中任意一个数,能得到另一个数。
- 两个相等的数 ^ 得到的结果为 0。
- 0 和任何一个数 ^ 得到的都是这个数本身。
应用: 交换两个变量的值
var a = 1
var b = 2
a = a ^ b
b = a ^ b
a = a ^ b
print("a = \(a), b = \(b)")
- i & 1 可以判断 i 最后一位是不是 1。
应用:求无符号整数二进制中 1 的个数
func countOfOnes(num: UInt) -> UInt {
var count: UInt = 0
var temp = num
while temp != 0 {
count += temp & 1
temp = temp >> 1
}
return count
}
var a: UInt = 3
print(countOfOne(num: a))
- i & (i - 1) 消除 i 最后一位的 1。
应用:判断无符号整数是否为 2 的整数次幂
func isPowerOfTwo(num: UInt) -> Bool {
return (num & (num - 1)) == 0
}
print(isPowerOfTwo(num: 2))
- i & j == 0 可以知道 i 的 第 j 位不是 1。
应用:分组
func divideTwoGroups(nums: [UInt], flag: UInt) {
var lostNum1Array: Array<Int> = []
var lostNum2Array: Array<Int> = []
for num in nums {
if (num & flag) == 0 {
lostNum1Array.append(Int(num))
} else {
lostNum2Array.append(Int(num))
}
}
print(lostNum1Array)
print(lostNum2Array)
}
divideTwoGroups(nums: [1,2,3,3,5,8,9,9], flag: 2)
- (i >> j) & 1 == 1 可以知道 i 右移 j 位后等于 1。
应用:给定一个集合,返回这个集合所有的子集
func getSubsets<T>(_ set: Set<T>) -> Array<Set<T>> {
// 1 << set.count 相当于 2^set.count
let count = 1 << set.count
let elements = Array(set)
var subsets = [Set<T>]()
for i in 0..<count {
var subset = Set<T>()
for j in 0..<elements.count {
// i = 5, j = 0时 101 >> 0 => 101 & 001 => 001 满足
// i = 5, j = 1时 101 >> 1 => 010 & 001 => 000 不满足
// i = 5, j = 2 时 101 >> 0 => 001 & 001 => 001 满足
if ((i >> j) & 1) == 1 {
subset.insert(elements[j])
}
// subset : ["A", "B"]
}
subsets.append(subset)
}
return subsets
}
print(getSubsets(["A", "B", "C"]))