3.2 用0和1表达机器中的数据:机器数
3.2.1 机器存储数据的一些限制
理解此部分内容的关键是理解机器中表示数据是受到机器字长的限制的。“机器字长”是指机器内部进行数据处理、信息传输等的基本单元所包含的二进制位数。机器字长通常是8位、16位、32位、64位等。
小知识
机器字长是衡量计算机性能的重要指标。计算机的核心部件是微处理器或者 CPU (CPU 中央处理单元,目前一个微处理器可能包括多个 CPU)和存储器。CPU 有 CPU的字长,存储器有存储器的字长,但二者需匹配。目前机器被区分为8位机、16位机、32位机、64位机,主要观察的是CPU的字长是8位、16位、32位还是64位。
示例2 将(56)十转换成二进制数。
解:(56)十=(111000)二 ①
(56)十=(00111000)二 ②
(56)十=(00000000 00111000)二 ③
(56)十=(00000000 00000000 00000000 00111000)二④
示例2中式①是没有考虑机器字长的情况;式②③④分别是按8位、16位、32位字长转换的结果。
不同字长的基本单元所保存的数据是有范围限制的,超出了其范围,则被称为“溢出”。溢出是一种错误状态,有溢出则说明用于表达数据的字长满足不了要求,此时可考虑用更大的字长来表示数据。例如,要用8位字长表达一个数500,则会“溢出”,因为8位字长表示的最大无符号数是255,此时就需要采用16位字长来表示。
用机器表示的数称为“机器数”。假如机器数表示的是无符号整数,则即是将该整数按规定字长转换成相应的二进制数。假设机器字长为n位,则其表达的无符号数X的范围是2n>X≥0。
示例3 给出8位、16位、32位机器数表达无符号整数的范围。
解:8位字长为28>X≥0,即0~255。
16位字长为216>X≥0,即0~65 535。
32位字长为232>X≥0,即4 294 967 295。
3.2.2 有符号数及符号的表达
机器数的原码、反码和补码
机器数也可用于表示有符号数,其数值用二进制表示,数值的正负号也可以用0和1表示,符号可和数值一样参与计算。用机器数表示有符号数通常采用补码的方式。
那什么是补码呢?这就要理解原码、反码和补码。
原码:机器数的最高位始终作为符号位,0表示正号,1表示负号。机器数的其余部分作为数值位,通过将真实数值转换成二进制获得。原码的一个特点是0有两个编码:0 0000000和1 0000000。
示例4 写出(+108)十和(-108)十的原码,机器字长分别为8位和16位。
解:首先将(108)十转换成二进制数为1101100。
按8位字长的机器数为,机器数的最高位即第8位为符号位:
(+108)十=(0 1101100)原码; (-108)十=(1 1101100)原码。
按16位字长的机器数为,机器数的最高位即第16位为符号位:
(+108)十=(0 000 0000 01101100)原码; (-108)十=(1000 0000 01101100)原码。
示例5 8位字长和16位字长的原码表示的数的范围是多少?
解:8位字长,其中,最高位为符号位,0表正号,1表负号;剩余7位为数值位,可看作无符号数,则其范围为27>X≥0,即0~127。因此8位字长原码表示的数的范围是-127~+127。再看16位字长,其中,最高位为符号位,0表正号,1表负号;剩余15位为数值位,可看作无符号数,则其范围为215>X≥0,即0~32 767。因此16位字长原码表示的数的范围是-32 767~+32 767。
反码:正数的反码与原码相同。负数的反码是在原码的基础上,符号位不变,数值位逐位取反形成。
示例6 写出(+108)十和(-108)十的反码,机器字长分别为8位和16位。
解:由示例4可知,8位字长,反码可在求出原码的基础上形成:
(+108)十=(0 1101100)原码; (-108)十=(1 1101100)原码。
按照反码的规则:
(+108)十=(0 1101100)反码; (-108)十=(1 0010011)反码。
按16位字长:
(+108)十=(0 000000001101100)原码(-108)十=(1 000000001101100)原码。=(0 000000001101100)反码; =(1 111111110010011)反码。
示例7 写出0的反码表示,假设机器字长分别为8位。
解:因0的原码有2个,故0的反码也有2个:0 0000000和1 1111111。
补码:正数的补码与原码相同。负数的补码是在反码的基础上,符号位不变,数值位最低位加1形成。补码的一个重要特性是((X)补码)补码=(X)原码。
示例8 写出(+108)十和(-108)十的补码,机器字长分别为8位和16位。
解:由示例6可知,8位字长,补码可在求出反码的基础上最低位加1形成如下结果。
(+108)十=(0 1101100)反码; (-108)十=(1 0010011)反码。
按照反码的规则:
(+108)十=(0 1101100)补码; (-108)十=(1 0010100)补码。
按16位字长:
(+108)十=(0 000000001101100)反码(-108)十=(1 111111110010011)反码=(0 000000001101100)补码; =(1 111111110010100)补码。
示例9 写出0的补码,假设机器字长分别为8位。
解:0的反码有2个,即0 0000000和1 1111111。但0的补码却只有1个。
0 0000000按正数的规则补码为(0 0000000)补码;
1 1111111按负数的规则补码为(0 0000000)补码。
示例10 (1 1111111)补码和(1 0000001)补码哪个数大?(0 1111111)补码和(0 0000001)补码哪个数大?(1 1111111)原码和(1 0000001)原码哪个数大?(0 1111111)原码和(0 0000001)原码哪个数大?
解:(1 1111111)补码=(- 0000001);(1 0000001)补码=(- 1111111);
则(1 1111111)补码>(1 0000001)补码;
(0 1111111)补码>(0 0000001)补码;
(1 1111111)原码=(- 1111111);(1 0000001)原码=(- 0000001)。
则(1 1111111)原码<(1 0000001)原码;
(0 1111111)原码>(0 0000001)原码。
示例11 (1 0000000) 补码的数值是多少?
解:由于0的原码有两个,而在补码中+0的补码和-0的补码都可用0 0000000表示,归为一种形式,则(1 0000000) 补码便被空出了,其应该表示多少呢?按次序其应表示-28。
因为
(1 0000001)补码<(10000010)补码<(10000011)补码<(10000100)补码,
所以理应有
(1 0000000)补码<(1 0000001)补码,
(1 0000001)补码=(- 1111111)= - (28-1),则(1 0000000)补码= -28。
示例12 已知8位机器字长,(X)补码= 1 0110111,问(X)原码=______?
解:由1 0110111最高位为1知这是一个负数的补码。再继续求1 0110111的补码可得到 1 1001001,则1 1001001即为(1 0110111)补码的原码。即:((X)补码)补码=(X)原码
归纳与对比如表3.1所示。
表3.1 带符号的机器数的表示示意
续表
3.2.3 扩展学习:小数点的表达
小数点的处理
在计算机中,带有小数点的实数可按两种方式来处理,一种是小数点位置固定,或者在符号位的后面,或者在整个数值的尾部,此称为“定点数”。前者说明机器数全为小数,后者说明机器数全为整数。小数点以默认方式处理并未实际出现在二进制数值表示中。另一种是小数点浮动,借鉴科学计数法,被称为浮点数。浮点数由3部分构成:浮点数的符号位,浮点数的指数位,浮点数的尾数位。下面以一个例子来说明。
示例13 用浮点数表示(+ 245.25)十。
解:第1步,将(+ 245.25)十转换成二进制得到(+11110101.0100);
第2步,将正号用0表示得到(0 11110101.0100);
第3步,做变换,将小数点移到符号位的后面、数值位的前面得到0.111101010100×2+8;
第4步,将指数部分变为二进制数得到0.111101010100×20 1000;
第5步,按符号-指数-尾数的形式写出得到0 0 1000 111101010100。
这里仅给出了十进制数表示成浮点数的思路和步骤,并未给出全部细节,包括尾数用多少位表示、指数用多少位表示、如何处理指数的符号位等。尾数的位数决定了数值表示的精度,而指数的位数决定了能够表示的数的范围。
细节化的浮点数表示如图3.1所示,浮点数依据表达数值的位数多少区分为单精度数和双精度数。单精度数,即普通浮点数,32位字长,即1位符号位,8位指数位和23位尾数位。双精度数,64位字长,即1位符号位,11位指数位和52位尾数位。
图3.1 机器数的小数点处理示意
示例14 说明图3.1(b)所示数的表示的产生过程。原始的数值为- 0.11101×2 -1001。
解:第1步,转换为- 1.1101×2 -1010;
第2步,将1101表示成23位尾数,得到11010000000000000000000;
第3步,处理指数部分-1010,加上01111111平移得01110101。01110101即为8位的尾数;
第4步,因此数是负数,故符号位为1;
第5步,完整写出便是1 01110101 11010000000000000000000。
说明:所有的浮点数,默认有整数部分的1和指数部分的基值2,因此被省略,默认存在无须表示,这样尾数部分可多表示1位,从而可提高浮点数的表示精度。通过将指数平移的办法,即将(-127,127)区间的数平移到(0,254)区间,可使指数都转变为正数,默认加了127(二进制为01111111),还原时减掉127即可,平移后就无须考虑指数的符号表示。64位的双精度数可采用类似处理。
示例15 继续完成示例13,表示成单精度数。
解:示例13的第5步,0 + 1000 .111101010100;
第6步,将尾数小数点右移1位,指数值减1,得到0 + 0111 1.111010101000;
第7步,将指数部分平移,即加01111111,得到指数部分10000110。
第8步,完整的单精度数为 0 10000110 11101010100000000000000。
3.2.4 扩展学习:减法是可以用加法实现的
减法的实现
机器数用补码表示有符号数,最大的优势:一是符号位与数值位一样参与计算,且能保证结果是正确的;二是可将减法转换为加法来执行。
下面举例说明补码的加减法,假设机器用1位表示正负号,用4位表示数值。
示例16 计算(+7)十+ (+3)十= (+10)十。
解:首先将数表示成补码:
(+7)十+ (+3)十= (0 0111)补码+ (0 0011)补码。
按照二进制计算(见图3.2(a)),可知结果为0 1010。符号位为0,说明是正数,而正数的补码即是原码,转换成十进制即(+10)十。
示例17 计算(-5)十+ (-7)十= (-12)十。
答:首先将数表示成补码:
(-5)十+ (-7)十= (1 1011)补码+ (1 1001)补码。
按照二进制计算(见图3.2(b)),可知结果为1 0100。符号位为1,说明是负数。再转换成原码,即1 1100。注意补码的补码即为原码。1 1100即为(-12)十。
示例18 计算(10)十 + (-3)十 = (7)十。
答:首先将数表示成补码:
(10)十+ (-3)十= (0 1010)补码+ (1 1101)补码。
按照二进制计算(见图3.2(c)),可知结果为0 0111。符号位为0,说明是正数。再转换成原码,即0 0111,为(7)十。
示例19 计算(-7)十+ (-12)十=______?
答:首先将数表示成补码:
(-7)十+ (-12)十= (1 1001)补码+ (1 0100)补码。
按照二进制计算(见图3.2(d)),可知结果为0 0111。符号位为0,说明是正数。这出问题了,两个负数相加,结果却是一个正数,这就出错了,称为“溢出”,在机器计算中错误情况是需要被识别出来的。怎么识别“溢出”与否呢?这是可以自动判别的。
溢出判断规则:两个不同符号数的补码相加不会溢出,即无论结果符号为0或1都是正确的。两个同符号数的补码相加,如果结果的符号与两个加数的符号相一致,则没有溢出,反之,如果结果的符号与两个加数的符号不一致,则一定溢出。
由此规则判断示例16、示例17和示例18,结果是正确的;而示例19则产生了溢出。通过自动判断是否溢出,机器是能够保证补码计算结果的正确性的。
图3.2 补码计算示意
怎样看出将减法变为加法来做呢?假设做X - Y,可转换为X + (-Y),然后将X和–Y转换为补码,再做加法。可用钟表示意这一过程:
假设现在标准时间是5点钟,钟表快了2个小时变为7点钟,可以倒拨2个小时(即7-2,做的是减法),也可以正拨10个小时(即7+10=17(去掉12即5),做的是加法)。在这里,12被称为“模”,超过12将自动减掉一个12,则10为-2相对于模12的补码,机器数的补码也是源于这个思想,这是计算思维源自生活的一个实例。
用补码表示,将减法转变为加法来运算,这样只要实现了二进制加法的自动化,便可实现二进制的任何运算的自动化:减法可转换为加法,乘法可转换为连乘,除法可转换为连减等,通过有效的编排都可以用加法实现。