本文总结如何对数字进行进制转换和位运算及其应用。
Last Modified: 2023 / 8 / 19
进制
对于任何一个数,我们可以用不同的进位制来表示。比如:十进数57(10),可以用二进制表示为11001(2),也可以用五进制表示为212(5),也可以用八进制表示为71(8)、用十六进制表示为39(16),它们所代表的数值都是一一样的。
二进制
计算机将各种信息存储为称为位的二进制数字流。无论您是处理文本、图像还是视频,它们都归结为 1 和 0。
Python 的按位运算符让您可以在最细粒度的级别上操作这些单独的数据位。您可以使用按位运算符来实现压缩、加密和错误检测等算法,以及控制Raspberry Pi 项目或其他地方的物理设备。通常,Python 将您与具有高级抽象的底层位隔离开来。在实践中,您更有可能发现按位运算符的重载风格。
十六进制
十六进制是计算机中数据的一种表示方法。它的规则是“逢十六进一”。
1个字节是
8位二进制数:
二进制8位:xxxxxxxx ,范围:00000000-11111111,表示0到255。
2位十六进制数:
一位16进制数(0-F),用二进制表示是xxxx,范围:0000 - 1111,表示:0到16。
16进制要表示1个字节,需要到255,此时就还需要第二位,0x3E。
所以1个字节=2个16进制字符,一个16进制位=0.5个字节。
转换
python内部以十进制进行运算,即二进制,八进制,十六进制,全是str 类型,而十进制为 Int 类型。
在某些情况下,需要被处理的原始数据也未必是二进制,则此时需要进制转换,比如二进制数字0b110000000000011101001111000100
, 等同于八进制数字0o6000351704
,等同于十进制数字805426116
, 等同于十六进制0x3001d3c4
。
数据类型
数字
给定的数据类型可能为字符串类型,此时需要做转换以将其转换为便于计算的数字类型,即 字符串 -> 数字
。
int
方法
-
int(str)
-
int(str, 8)
-
int(str, 16)
但是没有```int(str, 2)
示例
int(12)
# 12
int('12', 16)
# 18
# 等同于将十六进制的 `0x12` 转换为十进制的 `18`
eval
eval()
函数用来执行一个字符串表达式,并返回表达式的值 1。
以下是 eval()
方法的语法:
eval(expression[, globals[, locals]])
参数 | 描述 |
---|---|
expression | 表达式。 |
globals | 变量作用域,全局命名空间,如果被提供,则必须是一个字典对象。 |
locals | 变量作用域,局部命名空间,如果被提供,可以是任何映射对象。 |
方法
- eval(f"{str:b}")
- eval(f"{str:o}")
- eval(f"{str:d}")
- eval(f"{str:x}")
示例
eval(f"{2:b}")
# 10
# int
eval(f"{10:o}")
# 12
# int
eval(f"{17:x}")
# 11
# int
字符串
在某些情境下可能需要输出字符串类型的数据。为什么没有16进制int转化为string,可以这么认为不管什么进制,python在内部表示都是10进制,先转化为10进制在进行。如16进制int转化为string,str(0x12)
,首先变为str(18)
,再到18
。那么我想结果为’12’,怎么办?这其实就是10进制int转化为string,即hex(0x12)
。
- 数字 --> 字符串
bin()
oct()
str()
hex()
比如:
str(12)
>12
hex(18)
>0x12
等同于将十进制18
转换为十六进制的0x12
进制
原始输出
- X进制 --> 二进制
bin()
- X进制 --> 八进制
oct()
- X进制 --> 十进制
int()
int(str, X)
- X进制 --> 十六进制
hex()
比如:
int(0x3001d3c4)
>805426116
int('0x3001d3c4', 16)
>805426116
标准输出
- 仅数字
bin().replace('0b', '')
oct().replace('0o', '')
hex().replace('0x', '')
- 固定输出位数
'{:010b/o/x}'.format()
比如
'{:032b}'.format(0x3001d3c4)
码
原码、反码、补码
概念
- 原码
存在于人的大脑里。
是二进制的原始表示法。 - 反码
存在于人的大脑里。
二进制码0变1,1变0叫做反码。
反码用于原码补码之间的转换 - 补码。
在电脑中物理存在的只有补码。
用来做数据的存储运算,可以实现计算机底层的减法操作,因而提出(可以表达出一个数的正负),也就是说默认计算机只会做加法, 例:5+(-3) => 5 - 3
乘法、除法是通过左移<<
和右移>>
来实现
正数高位补0 负数高位补1。python中由于没有限制位数,所以高位的0和1是物理不存在的。
转换
- 正数:
原码 = 反码 = 补码 - 负数:
反码 = 原码取反(除高位)
补码 = 反码加1
反码 = 补码减1
原码 = 反码取反(除高位)
原码 = 补码取反加1
补码 = 原码取反加1
位运算
运算符
为了说明位运算运算符的运算规则,运算符
及其子标题内容以A=60=0b 0011 1100
和B=13=0b 0000 1101
来举例。
运算符的计算优先级从高到低,依次为~、&、^、|
按位与运算符 &
- 语法:
参与运算的两个值, 如果两个相应位都为1,则该位的结果为1, 否则为0。 - 举例:
A & B = 0b 0011 1100 & 0b 0000 1101 = 0b 1100
0011 1100
0000 1101
0000 1100
按位或运算符 |
如果为负数,则按其补码形式参加按位或运算符 |
运算。
- 语法:
参与运算的两个值, 只要两个相应的二进位有一个为1时,结果位就为1。 - 举例:
A & B = 0b 0011 1100 | 0b 0000 1101 = 0b 11 1101
0011 1100
0000 1101
0011 1101
按位异或运算符 ^
- 语法:
参与运算的两个值, 只要两个相应的二进位值不相同,则结果位为1,否则为0。 - 举例:
A ^ B = 0b 0011 1100 ^ 0b 0000 1101 = 0b11 0001
0011 1100
0000 1101
11 0001
按位取反运算符 ~
- 语法:
对数据的每个二进制位取反,即把1变为0,把0变为1 。~x
类似于-x-1
- 举例:
~A = -0b111101
0011 1100
1100 0011
左移动运算符 <<
- 语法:
运算数的各二进位全部左移若干位,由<<
右边的数字指定了移动的位数,高位丢弃,低位补0。 - 举例:
A << 2 = 0b 1111 0000
0011 1100
1111 0000
右移动运算符 >>
- 语法:
把>>
左边的运算数的各二进位全部右移若干位,>>
右边的数字指定了移动的位数。 - 举例:
A >> 2 = 0b 1111
0011 1100
1111
应用
按位与运算符 &
为了介绍按位与运算符 &
的应用,此处及其子标题以0x3001d3c4
来举例。
清零
快速对某一段数据单元的数据清零,即将其全部的二进制位为0,则只要与一个各位都为零的数值相与那么结果为零。。
- 清零所有bit
0x3001d3c4 & 0x0 = 0x0
提取指定位数
获得指定位数的数字。方法为,找一个数,对应X要取的位,该数的对应位为1,其余位为零,此数与X进行“与运算”可以得到X中的指定位。
0x3001d3c4
为十六进制,通过十六进制>>二进制
部分的方法使用hex(input).replace('0x', '')
拿到其数字位数为8
。
1位十六进制数字相对应4位二进制数字。
即0x3001d3c4
若转换为二进制应该为32位。
- 获得bit [20:0]
0x3001d3c4 & 0xfffff = 0x1d3c4
bit [20:0]为低位20位, 相当于0b 1111 1111 1111 1111
, 又或者0x FFFF
。 - 获得bit [4:0]
0x3001d3c4 & 0xf = 0x4
bit [4:0]为低位4位,相当于0b 1111
,又或者0xF
保留最后一个1
保留最后一个1到最低位的数字
~ 0x3001d3c4 & 0x3001d3c4 = 0
- 保留最后一个1
- 0x3001d3c4 & 0x3001d3c4 = 0x4
相当于0b100
判断奇偶性
与 1
做 &
运算,相当于仅保留最后一位bit数字。
在计算机中,位与的符号是 &
,运算过程是 false & false = false
,true & false = false
,true & true = true
,故任何一个数 & 1
的结果有 2:
-
0 & 1 = 0
-
1 & 1 = 1
-
2 & 1 = 0
-
3 & 1 = 1
… -
1234 & 1 = 0
-
4321 & 1 = 1
奇数的二进制表示的末位为 1
,偶数末位为 0
。故可以通过运算结果来判断给定数字的奇偶性。
下面,我们分析几个例子。3
和 987
都是十进制数:
3 & 1
在计算过程是:
11
01
---
01
所以 3 & 1 = 1
987 & 1
在计算过程是:
1111011011
0000000001
----------------
0000000001
所以 987 & 1 = 1
实例
- 比如在数据库中,获取所有奇数的
id
,就可以直接:
select id from mytable where id & 1
- 在编程中判断一个数是否为奇数:
int number = 789;
if (number & 1){
print("此数为奇数")
} else {
print("此数为偶数")
}
按位或运算符 |
为了介绍按位或运算符 |
的应用,此处及其子标题以0x3001d3c4
来举例。
使指定位数置1
找到一个数,对应X要置1的位,该数的对应位为1,其余位为零。此数与X相或可使X中的某些位置1。
- 翻转bit [7:0]
0x3001d3c4 | 0xff = 0x3001d3ff
bit [7:0]为低位8位, 相当于0b 1111 1111
, 又或者0x FF
。
按位异或运算符 ^
为了介绍按位异或运算符 ^
的应用,此处及其子标题以0x3001d3c4
来举例。
翻转指定位数
使特定位翻转 找一个数,对应X要翻转的各位,该数的对应位为1,其余位为零,此数与X对应位异或即可。
- 翻转bit [11:0]
0x3001d3c4 ^ 0xfff = 0x3001dc3b
bit [11:0]为低位12位, 相当于0b 1111 1111 1111
, 又或者0x FFF
。 - 翻转所有bit
0x3001d3c4 ^ 0xffffffff = 0xcffe2c3b
保留原值
- 保留所有bit
0x3001d3c4 ^ 0x00000000 = 0x3001d3c4
交换a和b
x = x ^ y
y = x ^ y
x = x ^ y
按位取反运算符 ~
为了介绍按位取反运算符 ~
的应用,此处及其子标题以0xd3c5
来举例。
使最后一位置0
~1
的值为1111111111111110
,再按&
运算,最低位一定为0。
因为“~”运算符的优先级比算术运算符、关系运算符、逻辑运算符和其他运算符都高。
- 使最后一位置0
0xd3c5 & ~1 = 0xd3c4
左移动运算符 <<
为了介绍左移动运算符 <<
的应用,此处及其子标题以0xd3c4
来举例。
- 翻倍
(0xd3c4 << 0x1) // 0xd3c4 = 0x2
右移动运算符 >>
为了介绍右移动运算符 >>
的应用,此处及其子标题以0x3001d3c4
来举例。
- 减半
0xd3c4 // (0xd3c4 >> 1) = 0x2
总结
使用0
和1
来简单总结运算符的语法。
1 & 1 = 1, 1 | 1 = 1, 1 ^ 1 = 0
1 & 0 = 0, 1 | 0 = 1, 1 ^ 0 = 1
0 & 1 = 0, 0 | 1 = 1, 0 ^ 1 = 1
0 & 0 = 0, 0 | 0 = 0, 0 ^ 0 = 0
-
&
: 有0
则0
-
|
: 有1
则1
-
^
: 同0
异1
-
~
: 前0
后1
, 前1
后0
-
<<
: 左1位乘2
-
>>
: 右1位除2
参考链接
写本文时有参考以下链接
% todo
【技巧总结】位运算装逼指南
leetcode—-位运算(python)
进制
二进制
十六进制
转换
Python 二进制,十进制,十六进制转换
Python int与string之间的转化
位运算
位运算与数的二进制 ( python, 位运算I )
按位与、或、非、异或总结
Python 位操作(Bitwise Operation) 详解
Python获取数字的二进制值