闲扯原码,补码和反码
始发于goal00001111的专栏;允许自由转载,但必须注明作者和出处
人类习惯使用十进制数进行数值计算,而计算机则采用二进制,所以为了让计算机帮助人类计算,首先要把十进制数转换为二进制数。本文以最简单的8位定点整数为例,分析了计算机存储和计算数值的方法。
地球人都知道,整数有正负之分,但计算机却只认得“0”“1”,不知道符号“+”和“-”,所以有必要用“0”“1”来表示“+”“-”。人们规定用“0”表示“+”,用“1”表示“-”。
这样,我们就可以表示出计算机能识别的整数了,我们把符号数值化后的二进制数称为机器数,相对应的,符号没有数值化(即仍用“+”“-”号表示)的二进制数称为真值。计算机只能处理机器数,不认识真值,真值是给人类看的。
机器数有三种编码形式,分别称为:原码,补码和反码。为什么要搞得这么复杂,那些计算机科学家真的是吃饱了没事干吗?且听我慢慢道来:
其实篇头已经介绍了机器码的一种形式——原码,它的特点是有效数值部分照抄真值,符号“+”“-”分别用“0”“1”表示。
例如,十进制数+6,它的真值是+000 0110(注意:8位二进制数最高位是符号位,所以其真值只有7位),对应的原码就是0000 0110。
又如,十进制数-6,它的真值是-000 0110,对应的原码就是1000 0110。
原码表示法比较直观,它的数值部分就是该数的绝对值,而且与真值的转换十分方便。但是它的加减法运算较复杂,当两数相加时,机器要首先判断两数的符号是否相同,如果相同则两数相加,若符号不同,则两数相减。在做减法前,还要判断两数绝对值的大小,然后用大数减去小数,最后再确定差的符号,换言之,用这样一种直接的形式进行加运算时,负数的符号位不能与其数值部分一道参加运算,而必须利用单独的线路确定和的符号位。要实现这些操作,电路就很复杂,这显然是不经济实用的。为了减少设备,解决机器内负数的符号位参加运算的问题,总是将减法运算变成加法运算,也就引进了反码和补码这两种机器数。
那如何将减法运算转化为加法运算呢?
首先引入 “模”的概念,“模”是指一个计量系统的计数范围。以我们每天用来算时间的时钟为例,时钟的计量范围是0~11,所以它的模就等于12。计算机也可以看成一个计量机器,它也有一个计量范围,即存在一个“模”。 机器字长为n位的计算机的计量范围是0~2^n-1,模=2^n。
“模”实质上是计量器产生“溢出”的量,它的值在计量器上表示不出来,计量器上只能表示出模的余数。例如,虽然时钟的模=12,但是在时钟的指针并不能真正指向“12点”,“12点”的位置和“0点”是重合的!用C语言表示就是12%12 == 0。
任何有模的计量器,均可化减法为加法运算。这是为什么呢?
仍然以时钟为例,假设当前时针指向10点,而准确时间是6点,调整时间可有以下两种拨法:
一种是倒拨4小时,即:10-4=6
另一种是顺拨8小时:10+8=12+6=6
在以12为模的系统中,加8和减4效果是一样的,因此凡是减4运算,都可以用加8来代替。