题目:
请实现一个函数,计算一个整数二进制表示中 1 的个数,例如:把 9 表示成二进制是 1001,有 2 位是 1
####方案一
判断该数最后一位是不是 1,然后把该数右移一位;这样每次移动一位直到这个数变为 0 为止。但是该思路有个问题就是该数是负数时,会变成死循环,因为负数的最高位是 1,即使右移之后,为了保证该数还是负数,仍会把最高位置为 1。
1 | extension Int { |
2 | var binaryOneNumber : Int { |
3 | var tmp = self |
4 | var count = 0 |
5 | while tmp != 0 { |
6 | if tmp & 1 == 1{ |
7 | count += 1 |
8 | } |
9 | tmp = tmp >> 1 |
10 | } |
11 | return count |
12 | } |
13 | } |
14 | |
15 | print(0.binaryOneNumber) //输出0 |
16 | print(9.binaryOneNumber) //输出2 |
17 | print((-9).binaryOneNumber)//死循环 |
####方案二
对方案一会产生死循环的一种改良,把该数首先与 1(即为 flag)做&运算判断判断最低位是否为 1,然后把 flag 左移一位,判断第二位是否为 1,直到 flag 为 0。在 4 字节的 Int 类型里也就是移动 32 次。
1 | extension Int { |
2 | var binaryOneNumber : Int { |
3 | var flag = 1 |
4 | var count = 0 |
5 | while flag != 0 { |
6 | if flag & self > 0{ |
7 | count += 1 |
8 | } |
9 | flag = flag << 1 |
10 | } |
11 | //如果是负数的话,最高位会统计不上,这里在加1 |
12 | if self < 0 { |
13 | count += 1 |
14 | } |
15 | return count |
16 | } |
17 | } |
18 | print(0.binaryOneNumber) //输出0 |
19 | print(9.binaryOneNumber) //输出2 |
20 | //这里输出63是正确的,mac os里Int是64位的,在64位里-9的补码是 |
21 | //1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 0111 |
22 | print((-9).binaryOneNumber)//输出63 |
####方案三
在二进制中,把一个整数减去 1 之后再和原来的整数做&运算,得到的结果相当于把该整数的二进制表示中最右边的 1 变成 0。因此可以每次都把n & (n - 1)的结果赋值为 n,直到 n 为 0 结束。
1 | extension Int { |
2 | var binaryOneNumber : Int { |
3 | var tmp = self |
4 | var count = 0 |
5 | while tmp != 0 { |
6 | //这里减一,不能直接用-,有可能会有溢出错误的 |
7 | //因为负数的最大值的补码形式是1000 0000...,此时在进行减1,就会有溢出错误 |
8 | tmp = tmp & (tmp &- 1) |
9 | count += 1 |
10 | } |
11 | |
12 | return count |
13 | } |
14 | } |
15 | print(0.binaryOneNumber) //输出0 |
16 | print(9.binaryOneNumber) //输出2 |
17 | print((-9).binaryOneNumber)//输出63 |
18 | print((-1).binaryOneNumber)//输出64 |