[College] 二进制与机器数的几种形式
二进制的定义
初次接触二进制,你可能会觉得发明二进制的人思路轻奇: 为什么要多此一举地用这种方式来表达数字呢?事实上计算机不像我们这样智能,CPU是一个包含上亿个精巧的晶体管的芯片集合,晶体管表达“感情”的方式很简单,就是通过高低电压(有电没电),低电压的时候表示0,高电压的时候表示1,因此最终能让计算机理解的就只有0和1而已。
接下来,我们来认识一下原码、反码、补码以及移码——
基本概念
原码
原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值。
比如如果是8位二进制:
[+1]原 = 0000 0001
[-1]原 = 1000 0001
因为第一位是符号位, 所以8位二进制数的取值范围就是:
[1111 1111 , 0111 1111]
转为十进制就是:
[-127 , 127]
反码
反码的表示方法是:
1> 正数的反码是其本身
2> 负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.
[+1] = [00000001]原 = [00000001]反
[-1] = [10000001]原 = [11111110]反
补码
补码的表示方法是:
1> 正数的补码就是其本身
2> 负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
[+1] = [00000001]原 = [00000001]反 = [00000001]补
[-1] = [10000001]原 = [11111110]反 = [11111111]补
移码
移码的表示方法是:
在偏移2^(n-1)的情况下只要将补码的符号位取反便可获得相应的移码表示。
[+1] = [00000001]原 = [00000001]反 = [00000001]补 = [10000001]移
[-1] = [10000001]原 = [11111110]反 = [11111111]补 = [01111111]移
为什么要使用这些不同类型的机器数来表示?
现在我们总算是对原码、反码、补码、移码这几位朋友熟悉了一些,那么为了进一步加深对它们的理解,我们就需要知道:为什么人们要使用不同的方式表达一个数?难度稍稍加大咯~
反码
计算机的所有计算本质上都是加法,然而若正负值相加时让计算机判断符号位来选择运算方式会使得加法电路设计变得复杂。
但是若直接让符号位参与运算又会带来 1 + (-1) = -2 (8位为例:00000001 + 10000001 = 10000010) 等等问题。
反码的提出就是为了解决符号位参与运算的加法问题。
反码的运算方法为循环进位,即最高位的进位要加到最低位来。
以8位为例:
11111110(-1) + 11111110(-1)
= 11111100 + 1
= 11111101(-2)
补码
对于刚刚的运算,反码是一个不完美的解决方案,有不近人意的问题。(emmm...)
以8位为例,00000000 和 11111111 都可以表示零,一个 +0,一个 -0。为了解决这个问题,引入补码来表示数值。
设计补码的原因是要解决数值0的问题。
先简单介绍一下模运算:
A与B进行模运算,A mod B 表示求A除以B后得到的余数。例如10 mod 3 = 1,2 mod 5 = 2。其中我们称B为“模”。
计算机表示数值是有范围的(范围用bit表示),当加法计算超过了 bit 的长度,就会产生溢出 ,溢出的部分消失,这和模运算恰好一致。
比如上限是 255,则 5 mod 255 = 5,260 mod 255 = 5。 我们可以就说,在8位的情况下,5 和 260 是等价的。
同理,在负数的情况下,我们可以用负数进行模运算的结果去表示负数本身,这样就相当于用正数 (负数的模运算结果为正数) 表示了负数。
根据模运算的运算法则,(a+b) mod m = [(a mod m) + (b mod m)] mod m,在 m 为最大值的情况下,数A mod m 的值就是 A 的反码。反码 + 1 等价于 m + 1 并不破坏等式,同时保证了符号的正确和 0 的正确表示。
利用这个原理,我们再来看看十进制数5与260,在二进制下:
5为[00000101],共8位;260为[100000100],共有9位,由于统一为8位二进制,因此最高的第9位溢出(这个“溢出”就相当于取模运算),存储为[00000100],这就相当于反码,我们再根据以上对于补码的定义,对其加上1,原数变为[00000101]——
这样一来,我们发现:在补码系统中,5与260确实是等价的!
怎么样,补码是不是很牛逼?
我们再举一个经典的时钟例子:
假设现在钟表时间是10点,要将它拨到6点,有两种拨法:
1、倒拨4个小时;
2、顺拨8个小时;
上面的时钟系统,就是一种模运算系统,模是12。在这个模12系统中,(10-4) mod 12 = (10+8) mod 12 = 6
上面的拨法也可以写为:-4 mod 12 = 8 mod 12
于是,我们可以说,8是-4对模12的补码。
得到结论:对于某一个确定的模,某数A减去小于模的另一个数B,可以用A加上(-B)的补码来代替!这就是补码借助加法运算实现减法运算的原理。
移码
移码常常用在浮点数值的二进制表示中。
浮点数的二进制表示比较特殊,整个二进制位分为三个部分:符号位(含数符和阶符)、阶码、尾数。
设阶码为 e,尾数为 m,则浮点的值为: m∗(2^e),其中的阶码就是用移码表示。
用移码表示的原因在于,阶码作为指数是有正负的,用移码表示能在不考虑符号的情况下比较浮点数大小。
如:(8位情况下) [11111111] 是最小值,[00000000] 是 0 ,如果不考虑符号,则 [11111111] > [00000000] 显然不方便。而用移码则:[11111111] -> [00000001],[00000000] -> [10000000] 大小一下就比较出来了。
阶码确定浮点数的取值范围,尾数确定浮点数的精度。