py3笔记34:位运算符

2023-06-16  本文已影响0人  _百草_

1、概述

计算机中数在内存中以二进制形式进行存储
位bit:计算机中处理数据的最小单位,其取值只能是0或1
字节Byte:计算机处理数据的基本单位,通常系统中一个字节为8位,即1Byte=8bit
=>位运算:直接对整数在内存中的二进制进行操作
=>执行效率高(在程序中尽量使用位运算进行操作)

序号 符号 描述 运算规则 实例
1 & 两位数都为1时,结果才为1 1&1=1,1&0=0,0&0=0
2 | 两位都是0时,结果才是0 1|1=1,1|0=1,0|0=0
3 ^ 异或 两个位相异为1,相同为0 11=0,10=1,0^0=0
4 ~ 取反 0变1,1变0 0=1,1=0
5 << 左移 各二进制全部左移若干位,高位丢弃,低位补0 11二进制=0b1011;左移:44,二进制:0b101100
6 >> 右移 各二进制全部右移若干位:正数左补0,负数左补1;右边移出的丢弃 >>1即/2

注意:计算机中位运算操作,均是以二进制补码形式进行

2、原码、反码、补码

原码:用最高位表示符号位,其余表示数值位的编码称为原码。(正数的符号位为0,负数的符号位是1)
反码:

补码:

1+(-1)=0
bin(1)=0000 0001
bin(0)=0000 0000
-1的二进制只有是:1111 1111 ;依次叠加进一,导致超出8位类似溢出,才能成立

==>负数num的二进制数(有符号数),则可视为无符号数的(2**n+num)的二进制数
a = -4
print(bin(2**8+a))  
# a=-1,0b11111111
# a=-4,0b11111100

3、应用

3.1 按位与&

应用1:与1按位与,可获取对应二进制数的最低位
应用2:与按位与,可使该数低位的一个字节清零

# 按位与&
a=1  # 补码 01
# b=-1 # 补码 11
b = 9 # 101
print(a&b) # 1
a=0  # 补码0
print(a&b) # 0

3.2 按位或|

def get_huo():
    # 按位或|
    a=9  # 补码 0000 1001
    b=20 # 补码 0001 0100
    print(a|b) #0001 0101
    print(bin(a|b))
    # 1+4+16
# 引申
def get_bin(num:int):
    # 求num的二进制数
    res_bin=""
    while num: # 辗转相除
        res_bin=str(num%2)+res_bin  # 
        num//=2  # // 整除
        print(res_bin,num)
    return res_bin
print(get_bin(10))  # 1010

3.3 按位异或^

不同为1,相同为0

# 按位异或
# 相同则为0,不同则为1
#       110 #  6
#       100 # 4
# 异或  010
a=6
b=4
# print(bin(6),bin(4))
print(a^b," ",bin(a^b))

特点:
1、a^0=a.即0与任意数按位异或都得该数本身
1^0=0;0^0=0
2、1与任意二进制位按位异或都得到该位取反(0变1,1变0)
1^1=0, 0^1=1
3、a^a=0.即任意数与自身按位异或都得0
4、ab=ba
5、(ab)c=a(bc)
6、abb=a(bb)=a^0=a

3.4 左移<<

高位丢弃(不包括1),低位补0。左移时舍弃的高位不包括1,则每左移一位,相当于该数乘以2。
<<= 移动后赋值

a=-10
# 1000 1010
# 反码(符号位不变,其他取反) 1111 0101
# +1 得补码 1111 0110
# 左移n位(n=2): 11 1101 1000
# -1: 11 1101 0111
# 取反(符号位不变,其他取反):10 0010 1000 即1000 1010 末尾加n个0
print(bin(a))
# print(a<<2) # -40 ;但是a本身不变仍是-10
a<<=2
print(a)  # -40
a<<=2
print(a) # -160

3.5 右移>>

将运算符各个二进制全部右移若干位,正数左补0,负数左补1,右边移出的位丢弃。
>>= 右移后赋值

a=10  # 0000 1010
b=-10 # 1111 0110
print(a>>2)
# 左移2位,高位补0:0000 0010
print(b>>2)  # -3
# 左移2位,高位补1,得补码 1111 1101;-1:1111 1100 ;反码(符号位不变,其他取反) 1000 0011

3.6 按位取反~

~0=1 、~1=0
应用:~a+1=-a 即对任意数按位取反后加1,得该数的相反数

a=10 # 0000 1010
# =>取反 1111 0101(负数的补码)
# =>-1:1111 0100 =>反码(符号位不变,其他取反):1000 1011(其为负数=-11)
b = -10 # 1111 0110 # 存储的补码=>取反:0000 1001(正数,=9)
print(~a) # -11
print(~b) # 9

4、二进制数的正负

  1. 看是否无符号数/有符号数

若是有符号数,开头第一位是符号位,1表示负数,0表示正数

  1. 看是如何存储在计算机中

本身是没有正负概念的;需要知道是原码还是补码,才能进而推断它的原始的值。如10101010 ,若是无符号,则值=170;若是有符号数,则值=-89???==>存储前是有符号数,则按有符号数处理,存储前是无符号数,则按无符号数处理

  1. 最后,看操作系统的位数

若是8位,1111 1111是-1;若是16位的FFFF 是-1;若是32位的FFFF FFFF 是-1


5、小数的二进制数

小数部分,将其乘以进制n,取出整数部分作为二进制表示第1位;依次类推,直到小数部分为0

特殊情况,小数部分出现循环,无法停止,则用有限的二进制位无法准确表示一个小数,这也是在编程语言中表示小数会出现误差的原因
引申:Py3浮点数取整

# print(bin(0.1)) # TypeError: 'float' object cannot be interpreted as an integer
def get_float_bin(f:float,n:int)->str:
    """
    求浮点数的二进制数
    :param f:
    :param n: 二进制小数的结果保留n位
    :return:
    """
    f_int=int(f) # 整数部分
    f_bin=bin(f_int)[2:]
    # 小数部分math.modf也是ok的
    f_float=f-f_int
    bin_a=""
    while f_float and n:
        f_float*=2  # 2进制
        bin_a+=str(int(f_float)) # 取整数
        f_float-=int(f_float)# 取小数位
        n-=1
    while n: # 不足则补0
        bin_a+="0"
    return f"{f_bin}.{bin_a}"

print(get_float_bin(10.6,12))  # 1010.100110011001

引申:二进制小数转为十进制小数

def get_float_shi(s:str,n:int)->float:
    """
    二进制小数转为十进制小数
    :param s: 二进制小数
    :param n: 十进制小数的精确度
    :return: 十进制小数,小数点后n位
    """
    i,f=s.split(".")
    i_shi = int(i,2)
    length=len(f)
    f_int=0
    flag=0.5
    for i in range(length):
        f_int+=int(f[i])*flag
        flag*=0.5
    # return round(i_shi+f_int,n)  # 10.6,保留了1位而不是10.60
    # return "%.2f"%(i_shi+f_int) # 10.60
    return eval("{:.2f}".format(i_shi+f_int))  # float()

a=get_float_shi("1010.100110011001",2)
# print(type(a))  # <class 'str'>=> <class 'float'>变为10.6
print(a)

参考:
1、位运算
2、负数的二进制表示方法
3、原码、反码、补码
4、小数的二进制表示法

上一篇下一篇

猜你喜欢

热点阅读