CSAPP学习记录2.1---数据表示与补码

一、补码的含义

我们首先介绍'10'的概念,这里所指的‘10’并不表示我们日常生活中使用的十进制中'十'这个概念,而是所有进制中产生进位后的第一个数。

例如:

  • 二进制:0,1,10
  • 四进制:0,1,2,3,10
  • 八进制:0,1,2,3,4,5,6,7,10
  • 十进制:0,1,2,3,4,5,6,7,8,9,10

因此,我们在某个进制固定位数下计算的时候,最大的数就是‘10’的前一个数字所组成的数字,比如十进制下1000以内的加减法,则999是最大的数,八进制下1000以内的加减法,777是最大的数,二进制下1000以内最大的数,则是111。

我们引出最大数的作用:在固定的位数下,该范围内使用最大值减去任何一个数都不会产生借位。

我们都知道计算机的ALU是由加法单元实现的,而加法只会产生进位,而不需要考虑借位。而我们现实中的减法运算则会产生借位操作。因此在实现减法的时候为了复用加法器,让加法器可以执行减法操作,就需要消除想办法消除减法的借位行为。

而前面提到的最大的数在进行减法运算时刚好不需要借位,因此一个想法自然而然的产生了,我们在进行减法运算的时候先加一个最大的数(我们假设为MAX),再减去一个最大的数,然后根据结合率,我们先使用最大的数减数进行计算,将结果被减数相加,就可以消除减数与被减数之间的借位了,但是最后减去MAX的时候还是会产生借位。因此我们考虑MAX + 1,因为MAX进位后产生的是1个1,剩余的全是0,这样就可以把借位全部消除了。
因此A - B 就转换为 A +(MAX - B)+ 1 - (MAX + 1)的形式。
因此MAX-B就叫做X的补码(X为该进制下的最大数字,比如二进制下X为1,十进制下X为9),即如果是在十进制下计算A-B,则MAX-B的结果叫做B对9的补码,如果是二进制下计算,则MAX-B的结果叫做B对1的补码

'10'后面跟位数-1个0是MAX + 1的结果,所以MAX-B + 1叫做B对‘10’的补码,也就是我们在计算机课本中常见的补码的概念。由于二进制的特殊性,二进制下MAX-B可以简单的转换为将B的各位取反,因此二进制下"补码"的计算,是将B的各位取反后加1

由上面的分析我们可以知道B的"补码"可以当作-B来使用,只要在最后减去一个MAX+1即可,即在三位下最后减去‘1000’,四位下减去‘10000’

但在上面需要注意,如果被减数小于减数,即产生一个为负的结果时, A +(MAX - B)+ 1 位数与原来相同,而 (MAX + 1)是多一位的,例如100-150, 100 +(999 - 150)+ 1结果是950,而 (999 + 1)是1000,此时虽然950与000的计算不需要借位,但是1000比950多了一个最高位,因此还是需要借位才能继续运算。

在这种情况下,我们再更换一下思路,使用减数减去被减数,得到结果再取负即可。即将A-B转换为B-A,再用上面的方式来消除借位。

下面我们以二进制为例,来举例说明计算机中补码的用途。

假设我们在二进制下进行8位以内的有符号数的运算,由上面的讲述,我们可以知道补码可以表示负数,因此8位二进制所表示的256种变化中有一半要用于去表示补码,即负数。而最高为1之后的数字刚好是128-256,因此这部分表示为补码的话刚好是127-1的补码,因此00000001-01111111的含义不变,表示1-127,而10000000-11111111的含义变为其所表示的补码的含义,即-128到-1(需要减100000000),00000000表示0。

(这里为什么要把一半的取值直接当作补码来用呢?我觉得是为了减少运算量,因为如果A-B扩展成A + (MAX-B) + 1 - (MAX+1)的形式会导致原来的一次运算变为多次运算,如果直接将一半的取值表示为另一半补码,这样在进行计算时就只进行一次运算即可。即将负数直接存储为其正数的补码,而不先存储为其正数的形式,在计算减法时再将其转换为负数,这样统一了计算,即计算机内只存在加法一种运算)

最重要的是,由于计算机只能存储8位,所以MAX + 1超出8位限制,因此相当于减00000000,所以在计算机内可以直接补码视为负数,而不需要再去减MAX+1,因为此时MAX + 1相当于计算机中的0,虽然在现实中相当于10000。

EG:

//计算8-16
//在8位情况下,8表示为00001000,而16表示为00010000,-16表示为11110000
//如果按照正常的减法来,则是8与16进行减法计算=>最终转换为8与(-16)的加法
//如果按照计算机中减法来,则是8与(-16)直接进行加法计算,最终结果取负
/*以8与16进行减法来展示这个过程
MAX为11111111
需要将运算转换为-(16-8)
计算MAX-8 + 1,即11111111-00001000 + 00000001 = 11111000
16 + 上一步结果:00010000 + 11111000 = 100001000
减去10000000: 100001000 - 100000000 = 00001000,即8
取负: -8
*/

/*计算机视角下:
计算MAX-8 + 1,即11111111-00001000 + 00000001 = 11111000
16 + 上一步结果:00010000 + 11111000 = 00001000
无需减去10000000,因为计算机截位相当于减掉了
取负,相当于0-8: 0 + 1111111 - 00001000 + 0000001 = 11111000
0 + 上一步结果:11111000。刚好为8的补码,即-8
但是此时相当于运算了两遍一模一样的运算,所以直接用补码表示-8,省去了重复的运算(这里是我猜的)
*/

二、数据表示

  • C语言中并未规定使用什么形式来表示数据,但一般计算机都采用补码形式。
  • C语言在执行一个运算时,若一个运算数为有符号的,另一个为无符号的,则编译器会生成无符号数的操作指令,即隐含的将有符号数转换为无符号数来进行操作。
  • 无符号数扩展时,高位补0,有符号数扩展时,高位补符号位(因为补码表示中,正数符号位为0,扩展时补0,等同于无符号数扩展,负数符号位为1,高位补1,刚好相当于扩充后的无符号数的补码)。
  • 在进行有符号加法时,会先将两个有符号数看作无符号数进行相加,再将结果转换为有符号数。因此,假设4位,则两个有符号正数x和y相加中结果是大于等于2的3次方的且小于2的四次方会溢出产生一个负数,其值等于(x+y) -2^3, 此时为正溢出,同理两个有符号负数相加结果绝对值大于等于2的3次方且小于等于2的4次方的会溢出产生一个正数,其值为(x+y)+2^3,此时为负溢出。例如:-8-5,由于-8小于等于-2的3次方,-8-5 = -13,其结果绝对值大于等于8小于16,因此负溢出,结果为-13+16 = 3.
  • 有符号乘法,假设机器3位,则乘积可能为6位,因此在进行乘法运算时,会将参数3位x与y,分别扩充到6位,进行乘法运算后,再截取最后3位。
  • 无论有符号数还是无符号数,乘以某个数时,如果该数的大小刚好为2的k次幂,则可以将乘法转换为移位操作,只需要将操作数左移k位即可,最后结果再进行截断。
  • 除法同理,无符号数通过逻辑右移(高位补0)K位,相当于除以2的K次幂的,有符号数通过算术右移K位达到除以2的K次幂的效果。但是需要注意当x/y结果为负时,需要向上取整,而不是向下取整,所以需要修正,对于x小于0,在右移之前先为x加上2的k次幂-1再右移K位。
  • IEEE表示浮点数时,指数部分的值为e,e减去偏移量才是最终计算浮点数时使用的E,设置偏移量的作用是为了表示负指数,因为8位时偏移量为127,11位时为1023,刚好为指数位数可表示的数据范围的一半减去一,这样8位指数由原来的可表示的指数范围0-254变为了-127到128。
  • 当指数位全0和全1时表示规格化以外的值,全0表示非规格化的值,即0-1之间的浮点数,全1时表示正负无穷以及Nan等值。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值