计算机要存储、处理数据首先要解决如何表示数据的问题,这一步是规定数据的表示规则,例如采用什么进制,如何表示整数,小数(浮点数),如何表示字符汉字等。
##### 按数制划分
生活中我们使用的是十进制,计算机中数据的使用的是二进制,也用八进制和十六进制。
除了以上还有:
当然,进制有很多,理论上讲可以有无限多种进制,只需满足一个条件,进制的基数>1
即可,如果使用一进制,那么,这个进制就和结绳计数差不多了,对表示大的数据无意义。
以上所述的进制均属于位置记数发,这种数的表示法发明归功于苏马连人或比伦人,后为印度人发展,这种发明对人类的文明的有巨大的意义,他使数的表示更为方便简答 [ 引 ] ^{[引]} [引],这种数的表示方法需要两个一个基底,例如十进制的基底是10
,二进制的基底是2
,其次是需要一些符号表示数,通常是阿拉伯数字,例如二进制使用0、1
,这些数都是小于基底的数。
在位置计数法中进制转换有个不变的规则:除基底取余数
,这是数是模基底的数,例如十进制转换为二进制就需要不断取模2的数。
二进制表示: [ N ] 2 = a n ∗ 2 n + ⋯ + a 2 ∗ 2 2 + a 1 ∗ 2 1 + a 0 ∗ 2 0 = N u m [N]_2 =a_n*2^n + \dots + a_2*2^2 + a_1*2^1 + a_0*2^0 = Num [N]2=an∗2n+⋯+a2∗22+a1∗21+a0∗20=Num
其中 a n , … , a 2 , a 1 , a 0 a_n ,\dots, a_2 , a_1 , a_0 an,…,a2,a1,a0 是二进制数序列(模2的数,即余数),
2 n , … , 2 2 , 2 1 , 2 0 2^n,\dots,2^2,2^1,2^0 2n,…,22,21,20 是二进制的权值,例如在十进制中 1 0 3 10^3 103表示1000的权值, 1 0 2 10^2 102表示100的权值。
示例:
十进制转换二进制
[ 25 ] 2 = [25]_{2} = [25]2= 25 2 余 1 ⇒ \frac{25}{2}余 1 \Rightarrow 225余1⇒ 12 2 余 0 ⇒ \frac{12}{2}余 0 \Rightarrow 212余0⇒ 6 2 余 0 ⇒ \frac{6}{2}余0 \Rightarrow 26余0⇒ 3 2 余 1 ⇒ \frac{3}{2}余1 \Rightarrow 23余1⇒ 1 2 余 1 \frac{1}{2}余1 21余1,最后在将余数倒置:11001
利用程序实现时模2取余,然后整除2,直至所转换的数为0,即可实现转换
二进制转十进制
[ 11001 ] 2 = 1 ∗ 2 4 + 1 ∗ 2 3 + 0 ∗ 2 2 + 0 ∗ 2 1 + 1 ∗ 2 0 = 25 [11001]_2 = 1*2^4 + 1*2^3 + 0*2^2 + 0*2^1 + 1*2^0 = 25 [11001]2=1∗24+1∗23+0∗22+0∗21+1∗20=25
二进制转八进制、转十六进制
[ 100110011101 ] 2 → 分 组 100 ‾ 110 ‾ 011 ‾ 101 ‾ → 计 算 4635 [100110011101]_2 \stackrel{分组}{\rightarrow} \underline{100}\ \underline{110}\ \underline{011}\ \underline{101} \overset{计算}{\rightarrow}4635 [100110011101]2→分组100 110 011 101→计算4635
[ 100110011101 ] 2 → 分 组 1001 ‾ 1001 ‾ 1101 ‾ → 计 算 99 d [100110011101]_2 \stackrel{分组}{\rightarrow} \underline{1001}\ \underline{1001}\ \underline{1101}\overset{计算}{\rightarrow}99d [100110011101]2→分组1001 1001 1101→计算99d
即约定机器中所有数据的小数点位置是不变的。通常以一个标准定义。
定点数可以表示纯小数
或纯整数
当表示的纯小数时, 小数点的位置在数的中间.
当表示纯整数时, 小数点的位置在数的右边(尾部).
把一个数的有效数字和数的范围在计算机的一个存储单元中分别给予表示. 这种把数据的范围和精度分别表示的方法, 相当于小数点的位置对比例因子(指数)的不同而在一定范围内可以自由浮动, 所以称为浮点表示法.
计算机中任意二进制表示为: N = 2 e . M N=2^e.M N=2e.M
其中N为任意二进制数,2位基数,M为尾数
尾数域的最高位为1
示例(按IEEE754标准):
[ N ] 2 = 0 00001111 ‾ 000 0000 0000 0000 0001 0010 ‾ [N]_2 = 0\quad \underline{00001111} \quad \underline{000\ 0000\ 0000\ 0000\ 0001\ 0010} [N]2=000001111000 0000 0000 0000 0001 0010
公式: $ N = 2^e.M$ , 其中0表示正数, e = 00001111 = 15 e=00001111=15 e=00001111=15, M = 000 0000 0000 0000 0001 0010 ‾ = 1.18 M=\underline{000\ 0000\ 0000\ 0000\ 0001\ 0010} = 1.18 M=000 0000 0000 0000 0001 0010=1.18 (如果M不为0, 则最高位为1), 所以 [ N ] 2 = 1.18 ∗ 2 15 [N]_2 = 1.18*2^{15} [N]2=1.18∗215
定义
定点小数: [ N ] 原 = { x , 1 > x ≥ 0 1 − x = 1 + ∣ x ∣ , 0 ≥ x > − 1 [N]_原 =\begin{cases}x\quad ,1>x \geq 0 \\ 1-x = 1+|x| \quad ,0\geq x>-1\end{cases} [N]原={x,1>x≥01−x=1+∣x∣,0≥x>−1
定点整数: [ N ] 原 = { x , 2 n > x ≥ 0 2 n − x = 2 n + ∣ x ∣ , 0 ≥ x > − 2 n [N]_原=\begin{cases}x\quad,2^n>x \geq 0 \\ 2^n-x=2^n+|x| \quad,0\geq x>-2^n \end{cases} [N]原={x,2n>x≥02n−x=2n+∣x∣,0≥x>−2n
举例
[ + 0.111 ] 原 = 0.111 [+0.111]_原 = 0.111 [+0.111]原=0.111
[ − 0.111 ] 原 = 1 − ( − 0.111 ) = 1 + ∣ − 0.111 ∣ = 1.111 [-0.111]_原=1-(-0.111) = 1+|-0.111|=1.111 [−0.111]原=1−(−0.111)=1+∣−0.111∣=1.111
[ + 111 ] 原 = 0111 [+111]_原=0111 [+111]原=0111, 第一位0标识正数
[ − 111 ] 原 = 2 3 − ( − 111 ) = 2 3 + ∣ − 111 ∣ = 1111 [-111]_原 = 2^3-(-111)=2^3+|-111|=1111 [−111]原=23−(−111)=23+∣−111∣=1111
如果不是用原码的计算公式, 则可使用我们熟悉的在最高位前面加上0或1表示正负也行, 注意定点小数的符号位.
补码可以将负数转化为正数, 从而将减法运算转换为加法运算.
通常求补码的方法: 符号位不变数值位取反后加1.
在补码的定义中, 原码与补码的转换与"模"运算有关(在数学中为同余数), 一个很好的例子, 钟表当前是4点, 如果想调到2点有两种办法: 向后退两个小时或者前进10个小时, 从例子中可以得到关系 4 − 2 = ( 4 + 10 ) m o d 12 4-2 = (4+10)mod \ 12 4−2=(4+10)mod 12 , 在关系中-2的补码就是10, 那么如何根据-2得到10呢? 12 + (-2) = 12 -2 , 这就推出了补码负数的定义公式:
[ x ] 补 { x , 2 n > x ≥ 0 2 n + 1 + x = 2 n + 1 − ∣ x ∣ , 0 ≥ x ≥ − 2 n [x]_补 \begin{cases} x,\quad 2^n>x \geq 0 \\ 2^{n+1}+x = 2^{n+1}-|x|, \quad 0\geq x \geq -2^n \end{cases} [x]补{x,2n>x≥02n+1+x=2n+1−∣x∣,0≥x≥−2n
公式中$2^{n+1} $相当于12, 这是一个所有的数都小于的数, 在二进制中 2 n + 1 − ∑ i = 0 n 2 i = 1 2^{n+1}-\sum_{i=0}^{n}2^i = 1 2n+1−∑i=0n2i=1, 所以模 2 n + 1 2^{n+1} 2n+1的值的范围是 0 0 0~ ∑ i = 1 n 2 i \sum_{i=1}^{n}2^i ∑i=1n2i.
忽略符号位(原反补转换符号位不变), 在数值位上原码与补码, 且和为 2 n + 1 2^{n+1} 2n+1. 示例 [ 101 ] 原 + [ 011 ] 补 = 1000 = 2 4 = 2 n + 1 [101]_原 + [011]_补 = 1000 = 2^4 = 2^{n+1} [101]原+[011]补=1000=24=2n+1
反码是为求补码而生.
如果直接将原码转换为补码需要计算, 在电路中实现计算是比较麻烦的, 然而在电路中将电平信号进行切换却很简单, 由此反码就诞生了, 作为一个球补码的过渡.
将原码转换为反码时, 符号位不变, 数值位取反.
将反码转换为补码时, 符号位不变, 数值位加1.
这个所加的1是怎么来的?
任意一个负数的二进制取反, 再与被取反数相加值为 ∑ i = 0 n 2 i \sum_{i=0}^{n}2^i ∑i=0n2i , [ 101 ] 原 + [ 010 ] 反 = 111 = ∑ i = 0 n 2 i ( n 为 二 进 制 的 位 数 ) [101]_原+[010]_反 = 111 = \sum_{i=0}^{n}2^i(n为二进制的位数) [101]原+[010]反=111=∑i=0n2i(n为二进制的位数)
忽略符号位, 任意位负数的二进制的补码与原码相加为 2 n + 1 2^{n+1} 2n+1, [ 101 ] 原 + [ 011 ] 补 = 1000 = 2 n + 1 [101]_原+[011]_补 = 1000 = 2^{n+1} [101]原+[011]补=1000=2n+1
补码减去反码, 即 2 n + 1 − ∑ i = 0 n 2 i = 1 2^{n+1}-\sum_{i=0}^{n}2^i = 1 2n+1−∑i=0n2i=1
因此可以看出, 在反码基础上求补码所加的1是他们之间的差值.
移码通常用于表示浮点数的解码.
假定定点整数为: e k e k − 1 … e 2 e 1 e 0 e_k\ e_{k-1}\dots e_2\ e_1\ e_0 ek ek−1…e2 e1 e0(其中最高位为符号位)
则定义公式: [ e ] 移 = 2 k + e , 2 k > e ≥ − 2 k [e]_移 = 2^k + e \quad,\ 2^k>e\geq -2^k [e]移=2k+e, 2k>e≥−2k
其中, [ e ] 移 [e]_移 [e]移为机器数, e e e为真值, 2 k 2^k 2k是一个固定偏移常数.
假设阶码数值部分为5位, 以 e e e 表示真值, 则: [ e ] 移 = 2 k + e , 2 5 > e ≥ − 2 k [e]_移 = 2^k + e \quad,\ 2^5>e \geq-2^k [e]移=2k+e, 25>e≥−2k
当 e = + 10100 e=+10100 e=+10100时, [ e ] 移 = 1 10101 [e]_移=1\ 10101 [e]移=1 10101; 当负数$e=-10101 $时, [ e ] 移 = 2 5 + e = 2 5 − 10101 = 0 01011 [e]_移 = 2^5+e = 2^5-10101 = 0\ 01011 [e]移=25+e=25−10101=0 01011 . 其中结果的第一位是符号位.
从以上例子看, 移码的符号位与原码、反码、补码相反.
校验码用来排错、纠错,常见的有奇偶校验码,海明码。
奇偶校验码是一种简单的校验码, 只具有排错功能。
最后一位是校验位
当偶校验:数据位中1的个数为奇数个,则校验位变成1,使整体中1的个数为偶数个;如果数据位中1的个数恰好为偶数个,则校验位为0,保持数据位中1的个数为偶数个。
当奇校验:数据位中的1个数为偶数个,则校验位编程1,使整体中1的个数为奇数个;如果数据位中1的个数恰好为奇数个,则校验位为0,保持数据位中1的个数为奇数个。
总结: 奇校验与偶校验对1的要求个数不同, 校验位变换相反。
Q&A 请指正!