300字范文,内容丰富有趣,生活中的好帮手!
300字范文 > python 正数变成负数_Python基础之位运算符(含原码反码补码的通俗解释)

python 正数变成负数_Python基础之位运算符(含原码反码补码的通俗解释)

时间:2023-06-01 22:09:43

相关推荐

python 正数变成负数_Python基础之位运算符(含原码反码补码的通俗解释)

目录

1 二进制

2 原码、反码、补码

3 位运算符

4 位运算符使用技巧

上回学习运算符时,漏了位运算符,因为位运算符理解起来稍微有点复杂,所以要单独写一篇~

要理解按位运算符,要先了解计算机进行存储和计算的底层逻辑。

因此我们从最基础的二进制说起。

1 二进制

只要学过计算机,就不可能不知道二进制。

我们知道,十进制是逢十进一,譬如11,左边的1在十位上,代表10,右边的1在个位上,就是1。

把1502这个数字拆开看,就是有1个1000,5个100,0个10,2个1,

,也就是说,十进制中的位数对应的就是10的幂,个位是0次幂,十位是1次幂,百位是2次幂,以此类推……

同理,二进制中的位数对应的就是2的幂,那么对于二进制下的1010,转化成十进制下的数,就是

用2进制数数,首先是0,然后是1,接下去是10,而不是2,因为二进制中只有0和1。

小白可以练习一下从0写到10,写完对一下结果:

2 原码、反码、补码

这三个码的产生,都和表示减法(负数)有关,他们的正数表示完全一样。

至于为什么为了表示个负数,出现了三个码,我们一个一个来说。

2.1 原码

日常生活中我们用负号(减号)解决了负数的表示问题,但在计算机中怎么加上这个负号呢?人们就想了个办法,用最高位存放符号,正数为0, 负数为1。

以4位二进值数为例,最高位是符号位,那么后面只有三位来表示数字。例如,0001表示1,要表示-1,就把最高位写成1,得到1001。

当用8位来表示一个整数时,从右往左数的第8位即为符号位,当用16位来表示一个整数时,从右往左数的第16位即为符号位。我为了少写点数字>.<,本文举例都用4位。

这种方法简单直观,但在减法运算中有问题。计算1减去1,就是0001和1001加起来,会得到1010,这是咋了?1加-1,等于-2?

因此原码无法进行减法运算。

2.2 反码

正数的反码和正数的原码完全一样,对负数原码的非符号位取反,就得到负数的反码(其实也就是将正数的反码统统取反),譬如+1的反码是0001,-1的反码就是1110。

此时我们计算+1和-1相加,即0001+1110=1111,正好是-0,相反数相加等于0,没有问题。

但此时一个0有了两种表示法,0000和1111,一个数两种表示,有点奇怪。

除此之外,虽然相反数相加没有问题,但是其他数的减法依旧不对劲,譬如0010+1110,等于10000,最高位1溢出,就是0000,所以2-1=0???

所以,这个码还是不行。

2.3 补码

正数的补码和正数的原码完全一样,负数的补码等于负数的反码+1。但是,反码加1并不是补码的真正来历,只不过补码恰好等于反码加1,这么计算更加方便而已。

关于补码的本质和定义,其实初看难以理解,但是仔细想想,会发现这就是自然而然、浑然天成的东西。

我很喜欢一个词,“十方圆满”,一直以来我的微信签名都是这四个字。那么,这个词讲的是怎样一种状态呢?

譬如,我们原地转个圈,就可以回到原点。 譬如,我们在地球上,一直往东走可以到达的地方,一直往西走,也可以到达。譬如,我们把时钟的时针往前拨180度,和往后拨180度,得到的结果是一样的。再譬如,爱因斯坦说,如果人能看到无限远,那么他就能看到自己的后脑勺。

我到底在说什么呢?

对于四位二进制数,最大只能存放4位,就只有0000-1111这么大的空间,就只用$2^4=16$种排列组合的方式,空间是有限的。那么,这个空间圆不圆满呢?我们想办法让它从线性变成圆就好了,理解它,就像是理解24:00就是00:00,360°就是0°一样。

先不管负数,假设我们有一条绳子,上面从左到右依次写着0、1、2…15、16,就像这样。

我们把绳子首尾相连,也就是把写着0和16的两端拧到一起,圈成一个圆。

这个圆上只有16个数字,16就等于0,这是为了方便后面和四位二进制数的16种排列组合相对应。

我们从0出发,顺时针走1个单位,得到1,逆时针走1个单位,得到15,1+15=16。同样的,顺时针走7个单位得到7,逆时针走7个单位得到9,7+9=16。这个16有个专业的叫法,叫做模。

这里的模是什么意思呢?简单举几个例子: - 24小时制下,24就是模。 - 转一圈360°,360就是模。 - 表上有12个刻度,12就是模。

现在看这个圆,从0开始顺时针转,数值越来越大,最后到15,再转一个单位,就又回到0,没有什么问题吧?

好,我们开始引入负数,并且把顺时针看成加法,把逆时针看成减法,这下会得到什么呢?

顺时针走1个单位,认为是加1,所以得到1,圆的右边还是1~7。逆时针走1个单位,就是减1,得到-1,同理,把圆的左边都填满,得到下图。

首先,距离0相同距离的数,相加等于0,这解决了相反数相加为0的问题; 其次,这个圆可以把减法转化成加法,a-b=c,其实等同于a+(16-b)=c,因为模是16。可以自己验证下,譬如1-2=-1(逆时针走2个单位),在这里就等价与1+14=-1(顺时针走14个单位)。

完美啊!接下来,我们把这个圆上的十进制数字,替换成二进制就好了。

问题来了,正数的二进制码毫无疑问,负数的二进制码要怎么推出来呢?还有,1对面那个问号应该是什么数字?在7和-7之间,应该是8呢,还是-8呢?

先不管那个问号是什么数,7的二进制码是0111,再加1,得到1000,问号处的二进制码应该是1000,再加1,就是10001,以此类推,我们就能补满整个圆上的码。

补完你会发现,-1本就该是1111啊!因为1111再加1,为10000,但因为四位,最高位的1溢出了,所以就得到0000,-1加1可不就是0吗!

相应的,我们可以验证-4加4,即1100+0100,等于10000,溢出位不算,0000啊!这种表示法下,所有的相反数相加都是0000~

再看看别的减法呢,譬如6-3,即0110+1101,等于10011,即0011,就是3~哈哈,都通过验证了呢!

现在就剩最后一个问题了,就是0的对面应该是什么?从7出发,加1应该是8,但是从-7出发,减1应该是-8,这个1000到底代表哪个数?

其实不难发现,圆的右边都是正数,最高位皆为0,左边都是负数,最高位皆为1,这有点像原码中人为定义的最高位是符号位,所以1000自然而然应该是-8。

虽然求补码的过程中没有特意留出一个符号位,但最终得到的补码却可以用最高位来判断正负。补码的符号位就是这么来的。

比比赖赖这么多,其实求补码没那么麻烦,可以汇总成一句话:正数补码不变,求负数补码用模减去其绝对值即可。

前面我们说过模是16,那么求a-b,其实等同于a+(16-b),所以求-b这个负数的补码,用16减b不就行了吗?比如说,求-2,就用16的二进制码减去2的二进制码。可是,四位二进制码的空间里,根本没有16这个数啊?没有就对了,因为它是模,也就是10000,在八位中16的表示是00010000。

那么,我们计算-2的补码,其实就转化成: 10000 -0010 =1110

2.4 小结

总结一下:

原码:将最高位作为符号位(0表示正,1表示负)。反码:如果是正数,则和原码一样;如果是负数,符号位为1,其余各位取反。补码:如果是正数,则和原码一样;如果是负数,将反码加上1。

很多文章在解释补码时,都是原码→反码→补码这样的思路。

先介绍最简单的原码,它方便人读数,但无法做减法,接着引申出反码,它是原码过渡补码的中间产物,但无法解决0的问题,最后引出补码,反码直接加1即可得到补码,这个码可以完美解决前面两个码的问题。但实际上我们也知道了补码的发展过程并不如此,之所以提供这样的思路,只是为了便于计算补码。

关于补码的定义和本质,我解释得挺业余的,举的例子也不够严谨,主要是为了方便自己理解和记忆。要看专业的解释,就得去找权威书籍或教材来看了。

3 位运算符

计算机底层在存储数据的时候,都是用补码存储,位运算符就是基于补码进行的计算,包括:

位逻辑运算符: 与&,或|,异或^,取反~。位移运算符:左移<< ,右移>> 。

a

下面我就用2和3,也就是0010和0011举例。

a

4 位运算符使用技巧

在日常工作中,用到位运算符的场景似乎不多,它能用来做什么呢?

4.1 按位与

通常,我们写程序判断奇偶数,是除以2看余数。现在可以用该数和1进行按位与,结果是1,就是奇数,是0,则为偶数。

def

4.2 按位或

任意数和1按位或,可以向上求最接近的奇数。

6

4.3 按位异或

一个数a,另一个数b进行两次异或运算,最后结果不变,即(a ^ b) ^ b = a。

5

因此用异或运算调换两个数字的值。

a

当然Python中其实可以用一行代码就完成交换。

a

简单的加密也可以用异或运算,比如实际密码是password,既怕忘了又怕直接写下来被别人看到,就可以用一个简单的key作为密钥,两者作异或运算,得到tip,把这个tip记到小本子里。忘记密码时,将key和tip做异或运算,就能得到原密码啦~

password

4.4 按位取反

对一个数按位取反,等于它的相反数减1。

~

对一个数两次取反,结果不变。

~~

4.5 按位左移

a左移b位,就是把a转为二进制后左移b位,后面缺位补0,相当于a乘以2的b次方,因为在二进制数后添一个0就相当于该数乘以2。

5

4.6 按位右移

a右移b位,就是把a转为二进制后右移b位,前面缺位补0,相当于a除以2的b次方,并向下取整。

14

计算机中的数是用二进制来表示的,因此位运算可以更直接、更高效地实现运算操作。对于乘2除2,二进制左右位移一下就搞定,速度非常快,所以尽量用位移来代替代码中的乘除。

最后注意一点,在Python中只能对整数进行位运算~

参考链接:

1)原码、反码、补码的产生、应用以及优缺点有哪些? - 张天行的回答 - 知乎

2)原码,反码,补码的深入理解与原理

3)Python位运算用途以及用法

4)js 中位运算的应用

5)位运算简介及实用技巧(一):基础篇

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。