负的二进制数
[日期:01-11][字体:大 中 小] |
二进制算术需要理解的另一个方面是负数。前面一直假定所有的数字都是正的。从乐观的角度来看是这样,所以我们目前已对二进制数有了一半的认识。但在实际中还会遇到负数,从悲观的角度来看,我们对二进制数的认识仅仅是一半。在计算机中,是如何表示负数的?我们只能按照自己的意愿来处理二进制数字,所以解决方案必须是使用其中的一个二进制数字。
对于允许是负数的数值(称为带符号的数值),必须先确定一个固定的长度(换言之,就是二进制数字的位数),再把最左边的二进制数字设置为符号位。必须固定位数,这样才能避免符号位与其他位的混淆。
因为计算机的内存由8位字节组成,所以二进制数字要存储在多个8位中(通常是2的幕),即有些数字是8位,有些数字是16位等。只要知道每个数值的位数,就可以到符号位,它应是最左边的那一位。如果符号位是0,该数值就是正的,如果它是1,该数值就是负的。
似乎这就解决了问题,但实际上并非如此。当两个整数相加时,计算机不应不检查两个数字是否为负。我们希望使用常规的“加”来生成相应的结果。如果把–8加到+12上,答案就应是+4。
如果用简化的解决方案来执行这一操作,也就是把正数的符号位设置为1,使它变成负数,再执行算术运算,并进行常规的进位,答案就是错误的:
12转换为二进制: 0000 1100
–8转换为二进制: 1000 1000
如果把它们加起来,结果是 1001 0100。
答案是-20,这可不是我们希望的结果+4,它的二进制应是0000 0100。此时读者会认为,“没有把符号作为另一个位”。但是,在用计算机进行计算时,这是必须要考虑的。因为计算机是哑巴,它们处理这种情况会出问题。我们需要用另一种方式来表示负数。
下面看看计算机如何表示–8,即从+4中减去+12,得到正确的结果:
+4转换为二进制: 0000 0100
+12转换为二进制: 0000 1100
从前者中减去后者,结果是 1111 1000。
对于右边的4位数字,必须借1,才能进行减法,这正是我们在执行十进制算术时所进行的操作。结果就是–8,即使它看起来不是–8,但其值的确是–8。再用二进制把该值与+12或+15相加,就会得到正确的结果。
在从4中减去12时,究竟进行了什么操作?实际上是对负二进制数值采用了2的补码形式。这里需要做一个约定,以避免解释它为什么有效。下面看看如何从正数中构建负数的2的补码形式,读者也可以自己证明这是有效的。现在回到前面的例子,给-8构建2的补码形式。首先把+8转换为二进制:
0000 1000
现在反转每个二进制数字,即把0变成1,把1变成0:
1111 0111
这称为1的原码形式,如果给这个数加上1,就得到了2的补码形式:
1111 1000
这就是从+4中减去+12,得到的–8的二进制表示。为了确保正确,下面对–8和+12进行正常的相加操作:
+12转换为二进制 0000 1100
–8转换为二进制 1111 1000
把这两个数加在一起,得到: 0000 0100
答案就是4。这是正确的。左边所有的1都向前进位,这样该位的数字就是0。最左边的数字应进位到第9位,即第9位应是1,但这里不必担心这个第9位,因为在前面计算-8时从前面借了一位,在此正好抵消。实际上,这里做了一个假定,符号位1或0永远放在最左边。读者可以自己试验几个例子,就会发现这种方法总是有效的。最妙的是,这使计算机上的算术计算
非常简单快速。
负数在计算机中的表示
今天,老大让我调查一个浮点数转换为整数的问题。自己就查了些资料,顺便复习一下原码、反码和补码。
原码:将一个整数,转换成二进制,就是其原码。如单字节的5的原码为:0000 0101;-5的原码为1000 0101。
负数二进制补码运算法则反码:正数的反码就是其原码;负数的反码是将原码中,除符号位以外,每一位取反。如单字节的5的反码为:0000 0101;-5的原码为1111 1010。
补码:正数的补码就是其原码;负数的反码+1就是补码。如单字节的5的补码为:0000 0101;-5的原码为1111 1011。
在计算机中,正数是直接用原码表示的,如单字节5,在计算机中就表示为:0000 0101。负数用补码表示,如单字节-5,在计算机中表示为1111 1011。
这儿就有一个问题,为什么在计算机中,负数用补码表示呢?为什么不直接用原码表示?如单字节-5:1000 0101。
我想从软件上考虑,原因有两个:
1、表示范围
拿单字节整数来说,无符号型,其表示范围是[0,255],总共表示了256个数据。有符号型,其表示范围是[-128,127]。
先看无符号,0表示为0000 0000,255表示为1111 1111,刚好满足了要求,可以表示256个数据。
再看有符号的,若是用原码表示,0表示为0000 000。因为咱们有符号,所以应该也有个负0(虽然它还是0):1000 0000。
那我们看看这样还能够满足我们的要求,表示256个数据么?
正数,没问题,127是0111 1111,1是0000 0001,当然其它的应该也没有问题。
负数呢,-1是1000 0001,那么把负号去掉,最大的数是111 1111,也就是127,所以负数中最小能表示的数据是-127。
这样似乎不太对劲,该如何去表示-128?貌似直接用原码无法表示,而我们却有两个0。
如果我们把其中的一个0指定为-128,不行么?这也是一个想法,不过有两个问题:一是它与-127的跨度过大;二是在用硬件进行运算时不方便。
所以,计算机中,负数是采用补码表示。如单字节-1,原码为1000 0001,反码为1111 1110,补码为1111 1111,计算机中的单字节-1就表示为1111 1111。
单字节-127,原码是1111 1111,反码1000 0000,补码是1000 0001,计算机中单字节-127表示为1000 0001。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论