Go:自定义比特位工具

本文介绍了如何使用Go语言中的位操作符(&、|、^、&^)来实现自定义比特位工具,包括判断奇偶数、设置某一位为1或0、比较正负符号以及检查二进制表示是否只有一个1。文中提供了详细的解释和示例代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

1、通过 & 实现

Ⅰ.判断奇偶数

Ⅱ.判断二进制表示某一位是否为1

Ⅲ.判断二进制表示是否只有一个1

2、通过 | 实现

Ⅰ.设置二进制表示的某一位为1

3、通过 ^ 实现

Ⅰ.判断两个数的正负符号是否相同

4、通过 &^ 实现

Ⅰ.设置二进制表示的某一位为0

5、测试代码

6.具体作用说明


注:本文实现自定义工具类,参考 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. 判断二进制表示某一个位置是否为1:在实际的设计当中,如果是只包含两个状态的某种属性,则可以通过二进制某一个位置是否为0来判断状态,比如说领奖状态,档位1:二进制数右起第一位,档位2:二进制数右起第二位....可以通过对应位置判断领奖状态
  2. 判断奇数偶数,正常使用.
  3. 设置二进制表示某一个位置为1:参考1,设置对应的领奖状态
  4. 设置二进制表示某一个位置为0:参考1,设置对应的领奖状态
  5. 判断一个数的二进制表示是不是只有一个1,用来判断这个数是不是2的N次方.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

了-凡

你的鼓励是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值