美文网首页
py3笔记34:位运算符

py3笔记34:位运算符

作者: _百草_ | 来源:发表于2023-06-16 21:07 被阅读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+(-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、小数的二进制表示法

    相关文章

      网友评论

          本文标题:py3笔记34:位运算符

          本文链接:https://www.haomeiwen.com/subject/kccvedtx.html