进制转换小技巧之让你重新认识二进制补码(大师,我悟了)!!!

前言

     我们都知道计算机内部是使用二进制来进行运算的,那么你对于二进制转换为其它进制或者其它进制数转换为二进制数是否熟练于心呢?

     与我们现实中的十进制不同,计算机内部使用二进制表示(一般我们书写用十六进制来展示,这样比较简洁,相比一大串01来说),也可以用ASCALL码表示,但它们都有一个问题:表示负数并不明显。所以我们需要了解另一种计算机内部的表示方法:二进制补码。

     对于求解二进制的补码,你是否存在诸多的疑问?例如为什么可以采用对原码求反码,之后加一得到补码的操作?为什么可以用十六进制10000减去负数的绝对值就得到负数的二进制补码表现形式?如果你有这些疑问的话,让我们一起来走进01世界吧(如果仅仅对二进制补码不解,请直接跳转到后半部分)。

 

进制转换技巧一窥:

1、对于二进制和十六进制的转换:

     首先对于二进制和十六进制来说我们都是直接转换的,毕竟每四位二进制就可以表示一位十六进制数,而十六进制数也是每一位表示四位二进制数。他们之间的转换诀窍就是将0~15的二进制十六进制表转换熟记于心即可。

2、对于二进制补码的转换:

  1. 对于无符号数(正数)来说,二进制的补码就是它本身,没有什么特别的,所以这里重点强调有符号数(负数的表示)
  2. 对于无符号数(负数)来说,计算机内部只有一种表示方法(就使用补码表示),但是有求解补码有两种方法,实际上我们自己手写的数字逻辑计算是一种,计算机内部计算又是一种:
  • 我们将其转换为十进制数(绝对值),然后转换为二进制得到原码,再对原码取反(也就是0变1,1变0),然后加一就得到了二进制补码--->这里我将它命名为方法一,它其实就是计算机内部进行的计算方式。
  • 我们先用十六进制表示这个数的无符号数(也就是取绝对值然后表示为十六进制数),然后用10000H(表示十六进制)减去这个数,就得到了该数的字长二进制补码表示--->命名方法二(这个才是最开始科学家想出来的计算方式,要了解这个方法,我们需要了解模的概念,可以直接关注下半部分。因为计算机内部是不可能进行取绝对值,减法运算的,所以计算机科学大佬们就想出了方法一的办法,让计算机来求解。)

    ------->我们可以用方法二来计算,用方法一来验算,这样做出来的结果一定就是正确的(但是我更加推荐直接方法二计算即可,因为它本来就是我们求解二进制补码的方法,只是为了让计算机可以理解我们的做法,才使用方法一这样的反码加一方式)。

 

一、二进制和十六进制一定要记住(或熟练导出)一表

十进制十六进制二进制
000
111
2210
3311
44100
55101
66110
77111
881000
991001
10A1010
11B1011
12C1100
13D1101
14E1110
15F1111

     把这个表写出来其实很简单,只需要记住十进制与二进制的转换即可,我们知道从右到左二进制的权值为2的幂次方,即1,2,4,8,16,那么对于十进制数13来说,转换为二进制数就可以看做是8+4+0+1即四位二进制最高位8为1,第二位为1,第三位为0,第四位为1,那么就是1101。对于4来说,直接100即可。所以此表就已经熟记于心了。

 

二、转换过程

十六进制十进制二进制补码
  0110
 -27 

识别正负数(有符号无符号数)技巧:

  •   对于十进制数的识别我们从小就知道,有负号就为负数
  • 对于二进制的识别,符号位即最高位为1(左边第一位)就为负数,反之为正数
  • 对于十六进制来说,如果左边第一位在[1,7],那么为正数(这个很好理解,因为十六进制和二进制随意转换,那么我们知道对于四位二进制来说,1~7最高位均为0,到8之后最高位就是1了),反之为负数。

(1)我们知道二进制补码0110,一看就知道是正数,那么二进制和十六进制是直接转换的,所以就有十六进制的数为6,那么十进制的数也是6。

(2)我们知道十进制数-27,首先我们用方法二将它取绝对值27,然后求27的十六进制数为1B(小技巧就是27=16+11,所以第一位为1,第二位就直接为B)。用十六进制100减去1B(这里也可以用10000字长,但100长度也就够了的)得到十六进制为E5,之后十六进制和二进制直接转换,那么就为1110 0101。

答案:

十六进制十进制二进制补码
660110
1B-271110 0101

 

三、转换原理总结:

     方法二用某个适当的2的幂的数作为减数(例如上面的十六进制100)减去负数的绝对值的十六进制数就得到了该有符号数的十六进制。因为任何时候对一个数求二进制补码,得到结果再对该结果求其二进制码就得到原数。用长度为字的数N表示有:

N = 10000 - (10000 - N)

     所以我们将负数取绝对值在用100减的时候,其实得到的十六进制数就是该负数的二进制补码数。

     如果我这样解释为什么可以这样计算负数的补码,你一定一头雾水,因为它仿佛只是告诉你一个结论,没有起因,也没有任何的中间过程。你所知道的手动计算负数的补码,无非就是让十六进制100减去这个数的绝对值。但why???

     首先我们理解一个原则,计算机肯定是为人类服务的,所以它内部的思想当然也是我们先有的思想,才想到如何在计算机内部实现,其次我们要理解,计算机肯定和数学密切相关的。那么我说这个话有什么用呢?我们慢慢看:

     上面说计算机大佬们的方法就是用10000减去负数绝对值从而得到二进制补码(当然,这里的负数绝对值和10000当然是十六进制啦)。如果你尝试使用原码、反码、补码的方式来解释这个方式,那你就走错方向了,因为我们总是先有前一个方式,才在计算机内部用反码的形式来求解(毕竟内部元件直接异或运算)。那在绝对值,加加减减的过程中,可能你会回忆起小学的补数操作,因为相加为最大数的两个数互为补数(小学的10、100等10^n),那么你想一下,相加为100000的两个数,如果互为补数(姑且那么说),那么我是不是可以直接这样去思考呢?当然是的!

     在密码学的时候接触到了“模”的概念,例如:钟表是有12个刻度的,现在是7点,我想将它减小到3点钟,你肯定有两个方法:一是你直接逆时针转动4个刻度到达3点(几乎所有人都会那么做吧);二就是顺时针转动8个刻度,也可以到3点钟。这里12就是模,也就是说7-3=4等价于12-4=8。这个时候你可能有了一点概念,那我们再来一个例子,例如90-10和90+90(相当于90+(100-10)))如果不考虑100进位的话,其实他们都是等价于80的,模就是100;对于10-80和10+(100-80)来说,不考虑100进位那么就是-70和30,显然两者不是一回事,于是圣贤们就想出用一半表示正数,一半表示负数的方式,也就是说,我们将100分为两份,一份为0~49,另一份为50~99(它其实表示的是-49~-1,注意这里有大小对应关系,即99代表-1),也就是98就是-2。是不是和我们的二进制表示一样,只是不同的是,老师会告诉我们最高位是符号位,表示正负,例如8位二进制有1000 0001即129,也可以看做是二进制补码表示的-1。

     那么上面我们看到互为补数的数在模的范围内做减法,可以将“X-Y”的减法运算变为“X+Y的补数”的加法运算

     我们回到计算机的二进制数、十六进制数来看,如果想要表示负数,那么我们可以表示为负数绝对值的补码形式。在这里,我们的10000其实就是相当于模(它是2的n次幂,相当于能够表达的最大的数值),而我们的运算肯定是在模的范围内,那么就可以看做是上面互为补数的数在模的氛围内是可以有负数变为绝对值补码形式的。为什么说10000相当于模呢,我们从上面隐约知道,模就是最大的(近似这么看),例如时钟的模就是12。0到100的数模就是100,那么对于计算机来说,模肯定就是2的n次幂,那么到底是多少呢?

     例如,8位二进制数一共可以表示2^8次方==256个数,即256就是8位二进制的模。照这么说,我们对于256之间的数的减法就可以看成是加上绝对值补数的加法。可是我们8位不是全部表示正数的,我们需要分出一半来表示负数,那么0~127就是128个数来表示正数,而-128~-1就表示负数部分。绝对不可以超过这个数字,否则8位的运算就溢出了,计算机内部会进行溢出的异或运算检测。

     那么我们来计算一下-128的补码,不就是256-|-128| = 128,而128的二进制不就是1000 0000。结合一下最初提出的十六进制的10000来计算,其实很好理解的,因为我们的模不都是2^n次幂吗?例如8位二进制的模就是2^8次幂==256,它的十六进制表示不就是100吗?而其它的位数进制的模也都是10000(后面根据位数进行添0操作,例如8位可以表示两个16进制数嘛,那100不就是最大的数值嘛,其实不够就在1后面添加0就好)。

     现在回到我们上面的例子,总结一下不就是一句话吗?——负数的表达方式就是它绝对值的补数。

     因为计算机内部不可以进行绝对值等运算,所以我们才使用原码、反码、加一的操作来达到我们上面算法的结果。就是我们手动计算十进制-27的时候,可以直接对它绝对值的十六进制求补码。而计算机内部是这样的:首先-27的原码是1001 1011,然后除符号位之外都01置换,即得到11100100,然后加一得到1110 0101。和上面我们手算的一对比,一样的对吧。

     当然有些老师求负数补码也有自己的技巧,例如对于-27来说,得到27的原码有0001 1011,之后从右往左除第一个遇到的1不变之外,其它都取反,也可以得到-27的补码,即1110 0101。但是它们的原理其实都是计算机大佬的负数的表达方式就是绝对值的补数的这个概念。对于10进制的说来说,我们总是熟悉10、100补数,对于2进制的数来说,我们也要熟悉十六进制的100、10000等模的概念。

 

     

总结:

     第三次修改之后这个就是最后的版本了,希望你能够理解补码的表示形式,对于我们计算来说它是一回事,对于计算机内部来说,又是另一回事。但是不得不说,补码的形式真的很好用,果然计算机大佬就是多呀。

 

小问题:

     发了文章之后,有人问为什么二进制负数能够表示的范围的绝对值总是比正数多一,其实这个也不是什么困难的事情。这里我就举一个8位二进制的例子,我们都知道它能够表示的范围是-128~-1,0~127。因为我们上面说过,8位可以表示256个数,为了能够表示负数,所以我们各取一半来表示正负数,即正数表示为0~127,而负数不就是-128~-1吗?

     在计算机内部,-1不就是对应1111 1111,它的真值不正是255吗?和我们上面所解释的原理是一致的。至于-128那么在计算机内部肯定是表示1000 0000啦。

     希望对你们有所帮助,有问题可以在讨论区一起讨论哦~

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

threecat.up

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值