今日在某一技术群里水群的时候,看到群友问了一个很有意思的问题如下所示:如果xx和yy是48位变量,将xx和yy分别用XX[]和YY[]来将这些数据分为六段进行保存我们该如何运算其差值。
强调一下仅限于人家是八位运算,不考虑用什么long来运算这些~~

那么最简单的想法也许就是 aa[i] = xx[i] - yy[i]了
但是这就会遇到一个最大的问题就是—— 假如xx[i] - yy[i] 是负数呢,而aa ,xx,yy都是u8即unsigned char 无符号字符类型的数据,那么假如xx[i]-yy[i]小于零必然会导致程序崩溃。

于是我提出了用一个额外的数组来专门存储这个符号位,众所周知,有符号的八位数据类型,其最高位是符号位,1代表负数,0代表正数,其数据范围是-128~127,而无符号字符型其最高位也用于计数,其范围为 0~256。
看似这个问题解决了,但是实际是不行的,在后续的计算中我们发现蕴含着巨大的问题。
如果我们想要计算石榴煎酒(16-9),6-9不够借1当十,16减9,6减9不够借1当十,16减9.....
好吧言归正传,以16-9举例,我们将数据四个字节四个字节运算,那么高四位就是0001 - 0000 就是 0001 ,低四位是0000-1001 那么我们把符号置1,用高四位的结果减符号,就是0000,低四位是1001-0000是1001就是十进制的9。那么最后的结果就是9啦~~


很显然,0111才是正确的结果,那么0111和1001是什么关系呢。哦!!!1001是0111的补码。突然间恍然大悟(死去的计算机原理正在攻击我)。
其实在计算机中,负数并不是简单的将数字最高位加上1 来表示的,而是用补码的形式表示的,补码的所有位翻转后+1就是原码了。
哦又想到刚才我们的操作,其实我们将6-9后得到的-3是一个负数,或者说0000-1001得到的负的1001是一个负数,而负数在计算机中的存储方式应该是以其补码的方式存在的。那么我们判断正负之后,如果是正数,那么应该用他的原码格式,如果是一个负数,那么我们就应该保存它的补码。
那么如此我们就可以完美的解决这个问题了。!
但这就结束了嘛(可恶字数才800还能水)
但是,为什么会有补码这么看起来反人类的东西呢???
这才是这期内容的主题——全减器
几乎所有编程里面的书都会向你介绍补码,反码,原码的概念,但是我几乎没有看到这些书对其做出解释(虽然好像也不重要)。但是当你了解到补码的意义时才会感慨道人类的智慧竟是如此伟大。

这是一个全加器,结构非常简单,Ai和Bi分别是加数作为输入端, Ci-1是上一个全加器的进位,Si作为本位,Ci作为给下一个全加器的进位,第一个全加器的Ci-1是0,再加上七个这样子的全加器就构成了一个八位加法器。结构非常的巧妙,被大量的运用在了计算机的底层,本质上计算机就是再做复杂的运算。
那么如何做减法呢???

我们可以利用138译码器来实现全减器,亦或者其他的结构。但是总不能我八位减法器就得用八个138译码器吧??
我们再来看回减法,减法的本质也是加法,比方说3-5其实就是3+-5那么我们能不能用全加器来实现加法呢?

当我们的数据采用补码时,我们即可实现将减法运算利用加法来实现,用补码来表示计算机的负数,使得硬件上可以节省减法器的开发,而我们前面提到,将 补码转换成原码的方式是取反加1 ,那么同样的我们需要计算减法时,只需要对其中的一个加数将其转换成补码,即 减一再取反 ,并且通过逻辑运算单元ALU来控制就可以实现减法运算了。

写到这不由感慨这些知识本是这学期初想和mlm手搓一块CPU而学习来的,可是这个学期事情繁多最终并未付诸实践。几个月前两个少年再研究CPU架构的时候,命运的齿轮就开始转动,也许教育和学习就是有延时性的,并不能当时获得满足,可是当这一切积累起来的时候,总有一个时刻总会为之前了解过的东西而感到惊讶。
这也让我悟了,其实本来没指望在大学的课堂中学到什么,但是没学明白和不了解是两码事,课堂上我所学的不仅仅是知识,而是新的视野。


登录 或 注册 后才可以进行评论哦!
还没有评论,抢个沙发!