• Python示例——负数的位运算


    平时在coding的时候虽然会遇到位运算但一般也都是正数的位运算,今天突然见到了使用负数的位运算,对此十分好奇和困惑,为此做了下了解,于是有了此文。

    给出一些位运算的例子:

     

    其中,正数的位运算是最为常见的,如:

    1<<0
    1<<1
    1<<2

    (1<<0)&2
    (1<<1)&2
    (1<<2)&2

    但是对于负数的位运算还是没有见过的,如:

    (1<<0)&-2
    (1<<1)&-2
    (1<<2)&-2

    搜索了下网上的资料,还真有这方面的解释:

    小敏学Python基础篇丨负数位运算的讲解

    答案就是:

    其实,负数在进行位运算时是以形式参与计算的。

    https://baike.baidu.com/item/%E8%A1%A5%E7%A0%81/6854613?fr=aladdin 可知:

    在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时,加法和减法也可以统一处理

    http://c.biancheng.net/view/290.html 可知:

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

    正数的原码、反码、补码均相同。


    负数的反码:把原码的符号位保持不变,数值位逐位取反,即可得原码的反码。

    负数的补码:在反码的基础上加 1 即得该原码的补码。

    ===============================

    扩展的知识:

    既然在编程语言中负数是以反码的形式参与计算的,那么负数是以几个字节的形式来表示的呢,不然他的反码形式怎么写呢?

    从上面的问题我们又引出了一个新问题,那就是python中int类型数据是几个字节的?

    计算机编程基础好的人应该会知道其实在编程语言中int类型字节数不仅与编程语言有关,也与硬件环境有关,比如:C语言的int类型字节数就受计算机硬件平台所影响。但是,在JAVA语言中不论在什么硬件平台上int类型的字节数都是不变的。有关int字节数这个问题,这些年很少有人讨论了,主要原因就是现在大家都是使用X86平台,这样就像C语言这样的编程语言在相同计算硬件下int类型字节数也是一样的。那么,在python语言中这个问题又是如何的呢?

     参考:https://blog.csdn.net/weixin_39997173/article/details/109947726

    import sys
    
    print(type(0), end=' ')
    print(sys.getsizeof(0))# 24
    
    print(type(1), end=' ')
    print(sys.getsizeof(1))# 28
    
    print(type(2), end=' ')
    print(sys.getsizeof(2))# 28
    
    print(type(2**15), end=' ')
    print(sys.getsizeof(2**15))# 28
    
    print(type(2**30), end=' ')
    print(sys.getsizeof(2**30))# 32
    
    print(type(2**128), end=' ')
    print(sys.getsizeof(2**128))# 44

     

    从上面的代码中,我们可以知道,python语言中int类型的字节数是不固定的,具体使用多少字节数是与这个int类型的表示大小有关的,具体解释见:https://blog.csdn.net/weixin_39997173/article/details/109947726

    既然我们知道了python中int类型的特性,那么在python中使用int类型进行位运算时我们不需要考虑int类型的表示范围。在参与运算的数为正数情况下,如果二元运算则需要考虑int类型的数值部分最大的那个数的二进制表示,并对数值部分小的那个数进行补0;如果是一元运算也只考虑数值部分的二进制表示,不需要考虑补0操作。如果参与运算的数为负数,先将其当做正数写出原码形式并补0,然后再对补0后的数的符号位置为负并求补码参与运算。

    具体操作:(0b代表符号位为正,-0b代表符号位为负

    1. 与、或操作

    与操作:

    -22 & -7 = -24

    -22的补码为-0b01010,7的补码为0b111,由于7的补码位数小于22,补0后得到7的补码为0b00111,因此参与计算的-7的补码为-0b11001,

    因此,参与与操作的两个数分别为-0b01010和-0b11001,因此得到运算结果的补码:-0b01000,(符号位参与运算)

    -0b01000求补码得:-0b11000,即-24。

    或操作:

    -22 | -7 = -24

     -22的补码为-0b01010,7的补码为0b111,由于7的补码位数小于22,补0后得到7的补码为0b00111,因此参与计算的-7的补码为-0b11001,

    因此,参与或操作的两个数分别为-0b01010和-0b11001,因此得到运算结果的补码:-0b11011,(符号位参与运算)

     -0b11011求补码得:-0b00101,即-5。


    2. 异或操作

    22 ^ 7 = 17

    22的补码为0b10110,7的补码为0b111,由于7为正数并且补码的位数小于22,于是对7的补码进行补0操作,得到:0b00111

    因此,参与异或操作的两个数分别为0b101100b00111,因此得到运算结果的补码:0b10001

    0b10001求补码得:0b10001,即17。

    -22 ^ -7 = 19

    -22的补码为-0b01010,7的补码为0b111,由于7的补码位数小于22,补0后得到7的补码为0b00111,因此参与计算的-7的补码为-0b11001,

    因此,参与异或操作的两个数分别为-0b01010和-0b11001,因此得到运算结果的补码:0b10011,(符号位参与运算)

    0b10011求补码得:0b10011,即19。

    3. 非操作

    ~10 = -11

    10的补码为0b 1010,对其取反操作得-0b 0101(此过程中符号位参与运算),得到我们想要的运算结果的补码形式;

    我们再对-0b 0101求补码即可得到想要的运算结果的原码形式:-0b 1011,即-11 。

    ~(-2)= 1

    -2的补码为-0b 10对其取反操作得0b 01(此过程中符号位参与运算),得到我们想要的运算结果的补码形式;

    我们再对0b 01求补码即可得到想要的运算结果的原码形式:0b 01,即 1 。

    ~(-3)= 2

    -3的补码为-0b 01,对其取反操作得0b 10(此过程中符号位参与运算),得到我们想要的运算结果的补码形式;

    我们再对0b 10求补码即可得到想要的运算结果的原码形式:0b 01,即 2 。

    4. 移位操作

    -7<<2

    7的补码为0b 111,因此,-7的补码为-0b 001对其左移2位得-0b 00100(此过程中符号位不参与运算),得到我们想要的运算结果的补码形式;

    我们再对-0b 00100求补码即可得到想要的运算结果的原码形式:-0b 11100,即 -28 。

    也可以这样计算:

    因为  7<<2 = 28,因此  -7<<2 = -28 。

    ===============================

    在python中由于int的表示范围是不固定的,因此如果参与位运算的int数为负,那么我需要给与其足够大的表示范围才可以,也就是说要对其正数表示下的数补足够的零;不过更为直接的方法就是按照C语言中的标准,对python中参与位运算的数直接使用一个较大的统一的表示范围,如:2**8以内的数用8个数位来表示,2**16以内的数用16个数位来表示,2**32以内的数用32个数位来表示。

    ----------------------------------------------

  • 相关阅读:
    [高级软件工程教学]总成绩排行榜(12.20更新)
    [高级软件工程教学]团队Alpha阶段成绩汇总
    ab & webbench
    httpClient 3
    xpath 定位补充
    命令补充
    feed4testng
    自动化测试架构整理
    识别元素
    appium小例子
  • 原文地址:https://www.cnblogs.com/devilmaycry812839668/p/16585239.html
Copyright © 2020-2023  润新知