目录
注:本文实现自定义工具类,参考 Go 的位操作
测试代码是瞎写的...
1、通过 & 实现
Ⅰ.判断奇偶数
奇数的二进制表示的最后一位是1,而偶数的二进制表示的最后一位是0,所以可以通过 & 1 的操作,实现判断是否为奇数或者偶数的操作。
举个例子就是:
8 : 0000 1000 判断8说不是偶数就是
0000 1000
& 0000 0001
= 0000 0000
结果是0,所以判断它是偶数
7: 0000 0111 判断8说不是偶数就是
0000 0111
& 0000 0001
= 0000 0001
结果是1,所以判断它是奇数
代码实现如下:
//判断num是不是偶数
func JudgeIfEven(num int) bool {
return num&1 == 0
}
//判断是不是奇数
func JudgeIfOdd(num int) bool {
return num&1 != 0
}
Ⅱ.判断二进制表示某一位是否为1
同样的道理,判断某一位是否为1,即让num & 对应位数为1的数,因为其他位数都是为0,所以 & 的结果除了指定位置,其他位置都为0.具体可参考上一例,代码如下:
//判断num的二进制表示某个位置是否为1
func JudgeOneWithPosition(num int, position int) bool {
if position < 1 {
panic(fmt.Sprintf("输入有误:Position不能小于1,当前出入的Position为%d", position))
}
return num&(1<<uint(position-1)) != 0
}
Ⅲ.判断二进制表示是否只有一个1
判断二进制是否只有一个1的表达式为: num&(num&(num-1)) == 0
本质上就是判断对应的数是否是2的N次方 ,首先解析一下 num&(num-1) 这个表达式,这个表达式有一个特点就是,当num 是2的N次方的时候,结果是0,所以再和num进行 & 操作结果一定是0
但是如果num不是2N次方的话, num&(num-1) 一定是不等于0的(并且最高为1的位置一定是1),所以再和num进行 & 操作结果一定不是0
举个例子就是:
8 : 0000 1000 num&(num-1) 就是
0000 1000
& 0000 0111
= 0000 0000
结果是0,因为如果是2的N次方的话,二进制表示只会有一个1,然后这个数-1之后,对应二进制表示为1的位置变成0,它右边的所有二进制位置都为1,所以导致 & 的结果是0.
10: 0000 1010 num&(num-1) 就是
0000 1010
& 0000 1001
= 0000 1000
结果是0000 1000可以看到 & 的结果本来最高的为1的位置是1,所以再和10进行 & 操作的时候一定是大于0
代码如下:
//判断一个数的二进制形式是否只有一个位置为1,这个方法可以用来判断是不是2的n次方
func JudgeOnlyOneBitWithOne(num int) bool {
//解析:num & (num -1) 当num为2的N次方的时候, 2N次方 & (2N次方 - 1) ,因为做了最高位的右移(2N次方只有一个1,2N次方-1除了2N次方的那一个1的位置为0,其他都为1)
//所以&的结果就是 0 ,而0 & 2N次方一定是0,所以如果结果是0,那么一定是2N次方,只有一个位置有1
//那么 num & (num -1) 当num不是2的N次方的时候,他的结果原来有1的最高位置,一定为1,所以再和num进行 & 操作的时候,结果也一定是大于0,所以不止一个1
return num&(num&(num-1)) == 0
}
2、通过 | 实现
Ⅰ.设置二进制表示的某一位为1
通过或操作设置某一个位置的二进制表示为1,因为或只要一个条件成立就行,所以当一个数与 1<< n 进行 | 的时候,对应的n的位置一定会被设置为1,这个操作有点像 num + (1<<n ).但是 | 相对来说应该更高效
举例如下:
9: 0000 1001
如果我要设置9的二进制表示第二位为1,则我的操作应该是 9 | (1<<1)
0000 1001
| 0000 0010
= 0000 1011
所以通过 | 的操作是可以实现设置进制位的,相当于替代了 + 的操作,具体代码如下:
//设置num的某一个位置为1,如果原来就是1的话,就不发生变化
func SetOneByPosition(num int, position int) int {
if position < 1 {
panic(fmt.Sprintf("输入有误:Position不能小于1,当前出入的Position为%d", position))
}
return num | (1 << uint(position-1))
}
3、通过 ^ 实现
Ⅰ.判断两个数的正负符号是否相同
异或是只有当两个数的二进制同一位置的标识不同的时候,才会返回1.
负数的二进制表示是先取正数的二进制表示的反码,再取补码,所以二进制表示的最高位一定是1(表示符号),正数的最高位为0(不超过int表示范围)所以两个数做 ^ 可以通过返回值判断正负符号是否相等
代码如下:
//判断两个数字的加减符号是否相同
func JudgeWithEqualSymbol(num1 int, num2 int) bool {
return num1^num2 >= 0
}
4、通过 &^ 实现
Ⅰ.设置二进制表示的某一位为0
&^ 的实际操作应该是 AND(a, NOT(b)) 即: a & (^b)
举个简单的例子
10 : 0000 1010
我要设置这个数的第2位为1,那么我要如此操作 10 &^ 1<<1 即 10 & (^(1<<1)
^(1<<1) : ^ 2
^ 0000 0010
= 1111 1101
这个时候再通过 10 去做 & 操作,就会有如下结果,因为 & 的后一个数字除了指定要为0的位置,其他位置都是1,所以& 操作之后,原来10的为1的位置还是1,为0的位置还是0,而指定位置必定为0
0000 1010
& 1111 1101
= 0000 1001
代码如下:
//设置某一个数num的二进制Position位为0
func SetZeroBuPosition(num int, position int) int {
if position < 1 {
panic(fmt.Sprintf("输入有误:Position不能小于1,当前出入的Position为%d", position))
}
return num &^ (1 << uint(position-1))
}
5、测试代码
/*
* @Author : huangzj
* @Time : 2020/12/3 14:11
* @Description:
*/
package bitOperation
import (
"fmt"
"testing"
)
func TestBitTool(t *testing.T) {
JudgeIfEvenTest()
JudgeIfOddTest()
JudgeOneWithPositionTest()
JudgeOnlyOneBitWithOneTest()
JudgeWithEqualSymbolTest()
SetOneByPositionTest()
SetZeroBuPositionTest()
}
func SetZeroBuPositionTest() {
fmt.Println("设置某个位置上的元素为0")
fmt.Println(fmt.Sprintf("原始: %16b", 1))
fmt.Println(fmt.Sprintf("结果:%16b", SetZeroBuPosition(1, 1)))
fmt.Println(fmt.Sprintf("原始: %16b", 10))
fmt.Println(fmt.Sprintf("结果:%16b", SetZeroBuPosition(10, 2)))
fmt.Println(fmt.Sprintf("原始: %16b", 20))
fmt.Println(fmt.Sprintf("结果:%16b", SetZeroBuPosition(20, 5)))
fmt.Println(fmt.Sprintf("原始: %16b", 101))
fmt.Println(fmt.Sprintf("结果:%16b", SetZeroBuPosition(101, 6)))
fmt.Println(fmt.Sprintf("原始: %16b", 20121))
fmt.Println(fmt.Sprintf("结果:%16b", SetZeroBuPosition(20121, 8)))
fmt.Println(fmt.Sprintf("原始: %16b", 821331))
fmt.Println(fmt.Sprintf("结果:%16b", SetZeroBuPosition(821331, 12)))
fmt.Println(fmt.Sprintf("原始: %16b", 821331))
fmt.Println(fmt.Sprintf("结果:%16b", SetZeroBuPosition(821331, 3)))
fmt.Println()
fmt.Println()
}
func SetOneByPositionTest() {
fmt.Println("设置某个位置上的元素为1")
fmt.Println(fmt.Sprintf("原始: %16b", 2))
fmt.Println(fmt.Sprintf("结果:%16b", SetOneByPosition(2, 1)))
fmt.Println(fmt.Sprintf("原始: %16b", 10))
fmt.Println(fmt.Sprintf("结果:%16b", SetOneByPosition(10, 1)))
fmt.Println(fmt.Sprintf("原始: %16b", 20))
fmt.Println(fmt.Sprintf("结果:%16b", SetOneByPosition(20, 1)))
fmt.Println(fmt.Sprintf("原始: %16b", 101))
fmt.Println(fmt.Sprintf("结果:%16b", SetOneByPosition(101, 4)))
fmt.Println(fmt.Sprintf("原始: %16b", 20121))
fmt.Println(fmt.Sprintf("结果:%16b", SetOneByPosition(20121, 6)))
fmt.Println(fmt.Sprintf("原始: %16b", 821331))
fmt.Println(fmt.Sprintf("结果:%16b", SetOneByPosition(821331, 11)))
fmt.Println(fmt.Sprintf("原始: %16b", 821331))
fmt.Println(fmt.Sprintf("结果:%16b", SetOneByPosition(821331, 2)))
fmt.Println()
fmt.Println()
}
func JudgeWithEqualSymbolTest() {
fmt.Println("判断两个数正负符号是否一致")
fmt.Println(JudgeWithEqualSymbol(10, 20))
fmt.Println(JudgeWithEqualSymbol(10, -20))
fmt.Println(JudgeWithEqualSymbol(-10, -20))
fmt.Println()
fmt.Println()
}
func JudgeOneWithPositionTest() {
fmt.Println("判断二进制表示的某个位上是否为1")
fmt.Println(fmt.Sprintf("%16b", 1))
fmt.Println(JudgeOneWithPosition(1, 1))
fmt.Println(JudgeOneWithPosition(1, 2))
fmt.Println(fmt.Sprintf("%16b", 10))
fmt.Println(JudgeOneWithPosition(10, 2))
fmt.Println(JudgeOneWithPosition(10, 3))
fmt.Println(fmt.Sprintf("%16b", 501))
fmt.Println(JudgeOneWithPosition(501, 7))
fmt.Println(JudgeOneWithPosition(501, 2))
fmt.Println()
fmt.Println()
}
func JudgeIfOddTest() {
fmt.Println("奇数的判断")
fmt.Println(JudgeIfOdd(1))
fmt.Println(JudgeIfOdd(2))
fmt.Println(JudgeIfOdd(101))
fmt.Println(JudgeIfOdd(200))
fmt.Println(JudgeIfOdd(91231))
fmt.Println(JudgeIfOdd(8321312))
fmt.Println()
fmt.Println()
}
func JudgeIfEvenTest() {
fmt.Println("偶数的判断")
fmt.Println(JudgeIfEven(1))
fmt.Println(JudgeIfEven(2))
fmt.Println(JudgeIfEven(101))
fmt.Println(JudgeIfEven(200))
fmt.Println(JudgeIfEven(91231))
fmt.Println(JudgeIfEven(8321312))
fmt.Println()
fmt.Println()
}
func JudgeOnlyOneBitWithOneTest() {
fmt.Println("判断二进制表示是不是只有一个位为1")
fmt.Println(JudgeOnlyOneBitWithOne(1))
fmt.Println(JudgeOnlyOneBitWithOne(2))
fmt.Println(JudgeOnlyOneBitWithOne(3))
fmt.Println(JudgeOnlyOneBitWithOne(4))
fmt.Println(JudgeOnlyOneBitWithOne(56))
fmt.Println(JudgeOnlyOneBitWithOne(64))
fmt.Println()
fmt.Println()
}
6.具体作用说明
- 判断二进制表示某一个位置是否为1:在实际的设计当中,如果是只包含两个状态的某种属性,则可以通过二进制某一个位置是否为0来判断状态,比如说领奖状态,档位1:二进制数右起第一位,档位2:二进制数右起第二位....可以通过对应位置判断领奖状态
- 判断奇数偶数,正常使用.
- 设置二进制表示某一个位置为1:参考1,设置对应的领奖状态
- 设置二进制表示某一个位置为0:参考1,设置对应的领奖状态
- 判断一个数的二进制表示是不是只有一个1,用来判断这个数是不是2的N次方.