C程序设计——计算机中如何表示负数

计算机中负数的表示方式,经常被提起的有三种:原码、移码、反码、补码

原码

原码,就是把二进制的最高位作为符号位(0:正号;1:负号),剩下的部分表示该数的绝对值。

我们以8位二进制举例:

eq?%5Cleft%20%28%20+1%20%5Cright%20%29_%7B10%7D%20%3D%3D%20%5Cleft%20%28%2000000001%20%5Cright%20%29_%7B2%7D%5C%5C%5Cleft%20%28%20-1%20%5Cright%20%29_%7B10%7D%20%3D%3D%20%5Cleft%20%28%2010000001%20%5Cright%20%29_%7B2%7D

如果扩展为16位二进制呢,就是下面这样:

eq?%5Cleft%20%28%20+1%20%5Cright%20%29_%7B10%7D%20%3D%3D%20%5Cleft%20%28%200000%270000%270000%270001%20%5Cright%20%29_%7B2%7D%5C%5C%5Cleft%20%28%20-1%20%5Cright%20%29_%7B10%7D%20%3D%3D%20%5Cleft%20%28%201000%270000%270000%270001%20%5Cright%20%29_%7B2%7D

从上面我们可以看到,原码负数从8位扩展到16位呢,需要再符号位的右边插入0,这个操作,硬件实现的时候,比较复杂。

再看一下原码的加法:

两个正数相加:直接加就行了

两个负数相加:绝对值相加,符号位不变

正数加负数:和的符号与绝对值较大的相同,和的绝对值等于较大的绝对值减去较小的绝对值。

可以看出来,原码整数的加法法则还是很复杂的。

反码

反码的正数,跟原码一样;负数,是把绝对值取反。

我们还以8位二进制举例:

eq?%5Cleft%20%28%20+1%20%5Cright%20%29_%7B10%7D%20%3D%3D%20%5Cleft%20%28%2000000001%20%5Cright%20%29_%7B2%7D%5C%5C%5Cleft%20%28%20-1%20%5Cright%20%29_%7B10%7D%20%3D%3D%20%5Cleft%20%28%2011111110%20%5Cright%20%29_%7B2%7D

如果扩展为16位二进制呢,就是下面这样:

eq?%5Cleft%20%28%20+1%20%5Cright%20%29_%7B10%7D%20%3D%3D%20%5Cleft%20%28%200000%270000%270000%270001%20%5Cright%20%29_%7B2%7D%5C%5C%5Cleft%20%28%20-1%20%5Cright%20%29_%7B10%7D%20%3D%3D%20%5Cleft%20%28%201111%271111%271111%271110%20%5Cright%20%29_%7B2%7D

从上面呢我们可以看到,反码从8位扩展到16位,只要看最高位就可以了,最高位是1,就再左边补8个1,如果最高位是0,就再左边补8个0,这个逻辑比原码简单多了。

我们研究一下取反的操作,前面我们学过,可以通过异或的方式,来给二进制取反,比如8位二进制取反:

eq?%5Cleft%20%28%2000000001%20%5Cright%20%29_%7B2%7D  ^  eq?%5Cleft%20%28%2011111111%20%5Cright%20%29_%7B2%7D ==eq?%5Cleft%20%28%2011111110%20%5Cright%20%29_%7B2%7D

我们也可以认为是:

eq?%5Cleft%20%28%2011111111%20%5Cright%20%29_%7B2%7D-%20%5Cleft%20%28%2000000001%20%5Cright%20%29_%7B2%7D%3D%3D%5Cleft%20%28%2011111110%20%5Cright%20%29_%7B2%7D 

再看一下反码的加法:

两个正数相加:直接加就行了

两个负数相加:两个数取反后相加,加完再取反。

正数加负数:负数取反后,与正数比较,若负数绝对值大,则负数绝对值减去正数后取反;若正数绝对值大,则正数减去负数绝对值,即为和。

我们可以看出来,反码整数的加法法则,也很复杂。

补码

补码的正数,跟原码一样;补码的负数,是把绝对值取反后再加1(即反码再加1)。

我们还以8位二进制举例:

eq?%5Cleft%20%28%20+1%20%5Cright%20%29_%7B10%7D%20%3D%3D%20%5Cleft%20%28%2000000001%20%5Cright%20%29_%7B2%7D%5C%5C%5Cleft%20%28%20-1%20%5Cright%20%29_%7B10%7D%20%3D%3D%20%5Cleft%20%28%2011111111%20%5Cright%20%29_%7B2%7D

如果扩展为16位二进制呢,就是下面这样:

eq?%5Cleft%20%28%20+1%20%5Cright%20%29_%7B10%7D%20%3D%3D%20%5Cleft%20%28%200000%270000%270000%270001%20%5Cright%20%29_%7B2%7D%5C%5C%5Cleft%20%28%20-1%20%5Cright%20%29_%7B10%7D%20%3D%3D%20%5Cleft%20%28%201111%271111%271111%271111%20%5Cright%20%29_%7B2%7D

前面我们说了,-1 取反操作相当于:

eq?%5Cleft%20%28%2011111111%20%5Cright%20%29_%7B2%7D-%20%5Cleft%20%28%2000000001%20%5Cright%20%29_%7B2%7D%3D%3D%5Cleft%20%28%2011111110%20%5Cright%20%29_%7B2%7D

-1 取反再加1呢,就相当于:

\left ( 11111111 \right )_{2}- \left ( 00000001 \right )_{2}+ \left ( 00000001 \right )_{2} \\==\left ( 1'0000'0000 \right )_{2}- \left ( 00000001 \right )_{2} \\\\==\left ( 256 \right )_{10}+ \left ( -1 \right )_{10}\\==\left ( 255 \right )_{10} \\==\left ( 11111111 \right )_{2}

大家发现没,补码这么一操作,就是《离散数学》中讲的“模256同余”,同余数有一个特点就是,加一个负数,相当于加上与它同余的正数,即把减法转化成了加法,或者说的抽象一点eq?%5Cleft%20%28%2011111111%20%5Cright%20%29_%7B2%7D,你可以认为是十进制数255,也可以认为是十进制数 -1,因为:eq?%5Cleft%20%28%20255%20%5Cright%20%29_%7B10%7D%5Cequiv%20%5Cleft%20%28%20-1%20%5Cright%20%29_%7B10%7D%5Cleft%20%28%20mod%20256%20%5Cright%20%29

由模运算的运算法则,补码的加法运算规则非常统一,不需要考虑符号位,两个数直接加就可以了。

也许你对上述结论不是很理解,也暂时不需要深究,随着学习的深入,特别是学习了《离散数学》后,你会逐渐对补码有更深刻的理解。

其实我们这样理解补码,它把\left ( 00000000 \right )_{2} ~\left ( 11111111 \right )_{2} 分成了两段: \left ( 00000000 \right )_{2} ~\left ( 01111111 \right )_{2} 和  \left ( 10000000 \right )_{2} ~\left ( 11111111 \right )_{2}

 \left ( 00000000 \right )_{2} ~\left ( 01111111 \right )_{2}就用来表示正数0\sim 127

 \left ( 10000000 \right )_{2} ~\left ( 11111111 \right )_{2} ,如果用来表示负数,再综合模256同余数:128\equiv \left ( -128 \right ) mod\left ( 256 \right )129\equiv \left ( -127 \right ) mod\left ( 256 \right )130\equiv \left ( -126 \right ) mod\left ( 256 \right )……255\equiv \left ( -1 \right ) mod\left ( 256 \right )。是非常不错的选择。

移码

移码,就是把二进制的值,减去一个约定值之后的差,作为该二进制表示的数值。

我们还以8位二进制举例,比如我们约定的值是127,那么\left ( 00000001 \right )_{2}表示的值就是:

\because \left ( 1 \right )_{10} == \left ( 00000001 \right )_{2}

并且1-127 == -126

所以当用二进制用移码表示数时:

\left ( 00000001 \right )_{2}==\left ( -126 \right )

移码的加减法,可能学过,但是都忘了,这里就不说了,感兴趣的同学,可以自己去查资料。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

十三香炖猪肉

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

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

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

打赏作者

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

抵扣说明:

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

余额充值