一文搞清二进制补码 丨【奔跑吧!JAVA】

举报
sjwy 发表于 2021/06/24 01:48:48 2021/06/24
【摘要】 引言    点进这个文章说明你对补码的概念也有不清楚的地方,嘻嘻,那就继续看下去吧。    很多同学在学习二进制的时候对于补码的理解不是很清楚,并且也不知道为什么补码是原码先取反然后再加一,这里就来说说我自己的理解,希望能帮到你。二进制    我们知道计算机内部使用二进制用来表示,准确来说,计算机内部只有二进制,只有0和1,再也没有别的数字了。0和1分别对应低电平和高电平,在磁盘中则代表S极...

引言

    点进这个文章说明你对补码的概念也有不清楚的地方,嘻嘻,那就继续看下去吧。

    很多同学在学习二进制的时候对于补码的理解不是很清楚,并且也不知道为什么补码是原码先取反然后再加一,这里就来说说我自己的理解,希望能帮到你。

二进制

    我们知道计算机内部使用二进制用来表示,准确来说,计算机内部只有二进制,只有0和1,再也没有别的数字了。0和1分别对应低电平和高电平,在磁盘中则代表S极和N极,也可以理解为正 和 反,总之0和1是不一样的两种状态,凡是界限分明的两种状态都可以用来表示0和1。

    二进制数包括有符号数和无符号数,这里我们讨论有符号数(因为无符号数也不牵扯补码的问题)。我们知道一个byte占用一个字节,也就是8个bit,在一般的编程课程中一般都会告诉我们,1byte所能表示的数字是2^8= 256个,又因为有符号数中第一位是符号位,第一位是0则代表正数,为1则代表负数,全为0则代表0,所以byte所能表示的范围是-128~127。这里比较精明的同学就会有疑问了,为什么是-128~127而不是-127~128?这将在下面讲解,请继续往下看。

补码的由来

    要了解为什么使用补码,那么我们就要知道如果不使用补码会遇到什么样的问题,举个例子大家就明白了,为了方便阅读,我们采用8个bit进行演示,多个字节的情况类似。

    比如00000000(8个0)表示0,00000001表示1,01111111表示127,那么按照常规的想法,10000001应该表示-1,10000000应该是-0(也就是0),11111111应该是-127。如下表:

二进制数值 对应的十进制数值 二进制数值 对应的十进制数值
00000000 0 10000000 -0
00000001 1 10000001 -1
00000010 2 10000010 -2
01111111 127 11111111 -127

    在计算机中也要遵循传统的数学定理,比如1-1 = 1+(-1) = 0,然而按照刚才的设想,00000001+10000001 = 10000010 = -2 ≠ 0,这违反基本的数学规律,这在一个科学的、自洽的计算机系统中是不允许存在的,这是存在的第一个问题;

    第二个问题是,+0和-0占据了两个位置,这样就无法表示256个数了,只能表示255个。

    那么我们需要怎么解决这个违反数学规律的问题呢?我们当然难以解决,幸好已经有伟大的计算机科学家找到了完美的解决方案,那就是补码。补码的规则是源码按位取反得到反码,然后再加1,就得到补码。补码与原码互为对称关系,即补码是原码的补码,原码也是补码的补码,这句话有点绕口,多读几遍就理解了。同理,原码与反码也是对称关系,反码是源码的反码,源码是反码的反码。

    我们再举例子,00000001(1)取反得到11111110,再加1得到11111111,然后将00000001 + 11111111 = 00000000 = 0!!!   所以11111111即为-1

                             00000010(2)取反得到11111101,再加1得到11111110,然后将00000010 + 11111110 = 00000000 = 0!!!   所以11111110即为-2

                             01111111(127)取反得到10000000,再加1得到10000001,然后将 01111111 + 10000001 = 00000000 = 0!!!   所以10000001即为-127

                             。。。以此类推就可以得到-1~-127所对应的二进制编码,并且满足负数的首位(符号位)是1。

     最后还剩一下一个10000000和00000000,00000000对应0,那么只剩下一个-128和10000000对应,那么为什么把10000000分配给-128而不是+128?这是因为10000000 + 00000001(1) = 10000001 = -127 ,所以10000000就等于-127 - 1 = -128。至此为止,8bit的所对应的所有的256个二进制数均与十进制数对应完毕,且完全满足数学规律,这就是我们想要得到的。

关键结论

    从上面的例子不难看出,满足数学规律的情况下,

       补码所代表的就是原码的相反数,补码所代表的就是原码的相反数,补码所代表的就是原码的相反数!!!

    重要的事情说三遍。

可逆性验证

    进行补码的逆运算: 11111111(-1) 减1得到  11111110,然后按位取反得到 00000001 (1)

    进行补码运算:11111111 (-1)取反得到 00000000,再加1得到 00000001(1)

    这里表明了两种运算的方式,都可以得到-1 的相反数 1,两种运算都可以,是等价的,这也就是取补码的两种方式,也就是得到相反数的方式。这里只是举个例子,其他情况下也是符合的,请大家自行验证。

    这里只是举8个bit位来说明问题,int表示4个字节,long表示8个字节的情况大家可以自行脑补。

常见数值的换算对比表

    下表列出常用的几个数的二进制与十进制的对应关系:

二进制数值 对应的十进制数值 二进制数值 对应的十进制数值
00000000 0 10000000 -128
00000001 1 11111111 -1
00000010 2 11111110 -2
00000011 3 11111101 -3
01000001 65 10111111 -65
01111110 126 10000010 -126
01111111 127 10000001 -127

结语

    结尾了,还有一个疑问没有解决,为什么是这么复杂的计算公式,先取反再加1来得到补码?

    这是因为取反之后的反码与原码相加会得到11111111(8个1),再加1,就会得到00000000(8个0,也就是0,限定8位,多余的一位会被计算机丢弃),两个数相加为0,这就是相反数的特质,所以依靠这种方式能得到和为0,也就能得到相反数。这样计算之后得到的结果有完美的的可逆性与逻辑性,也满足了数学规律并且没有重复分配,如此精妙绝伦,完美结合了数学特征和计算机的特质,真的佩服老一代计算机科学技术的睿智与深邃的智慧。

    为什么这些计算机科学家可以这么有智慧,设计出这么完美的公式,而我等只能瞻仰学习他们的成果?我想这是厚积薄发的结果,有了深厚的知识底蕴,才能遇到事情想到最佳的解决方案,完美解决问题。而我们需要做的,就是不断提高知识水平,夯实底蕴,在不断的磨砺锻炼中提高自己,同时对于细节要多练习达到熟能生巧,保持兴趣与竞争力,等待厚积薄发的机会到来,一举成名世人知。谢谢大家!

    本文有点啰嗦,这也是为了照顾零基础小白,如果能帮到你,这将是我莫大的荣幸。如果有问题可以评论加私信来和我讨论,我看到的话会及时回复。本人也是初来乍到,希望能得到各位大佬的指点。谢谢!

【奔跑吧!JAVA】有奖征文火热进行中:https://bbs.huaweicloud.com/blogs/265241

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。