本章主要研究三种重要的数字表示,分别是无符号编码、补码编码和浮点数编码。其中,无符号编码表示大于或等于零的数字,补码编码用来表示有符号整数,浮点数编码是科学计数法的以2为基数的版本。linux
特殊的转换方法数组
当值x是2的非负整数的n次幂时即 \[x=2^n\] 能够将x写成1后面加n个0的形式。
当n表示为 n=i+4j 时(0<=i<=3),x对应的十六进制数字能够写成一、二、四、8后面跟J个0
例如: \[ 512 = 2^9 \] 知 n=1+2*4 故2048对应的16进制是 0x200函数
下面show_bytes
函数的做用是打印出每一个以十六进制表示的字节,其中输入是一个字节序列的地址。学习
void show_bytes(byte_pointer start,size_t len) { size_t i; for(i=0;i<len;i++) { printf("%.2x",start[i]); } printf("\n"); } void show_int(int x) { show_bytes((byte_pointer)&x,sizeof(int)); }
实现的功能就是输出int型每一个字节对应的十六进制表示。优化
布尔运算 逻辑运算 命题逻辑 ~ NOT ┐ & AND ∧ | OR ∨ ∧ 异或 ⊕
【注】注意区分C语言中的逻辑运算与位级运算编码
C语言的逻辑运算是|| &&和!,分别对应命题逻辑中的OR、AND和NOT运算。逻辑运算认为全部的非零值都为真,参数零表示假,运算结果只由0和1。
逻辑运算中若是第一个参数求值就能肯定表达式的值,逻辑运算不会对第二个参数求值spa
几乎全部的编译器/机器组合都会对有符号数使用算数右移,而对于无符号数,右移必须是逻辑右移。操作系统
无符号数只能表示非负数,而补码编码可以表示负数、0和正数。指针
无符号数的编码code
无符号数的定义
对于向量 \[ \vec{x} = [x_{w-1},x_{w-2},\cdots,x_0] \] 有
\[B2U_w (\vec{x}) = \sum_{i=0}^{w-1}x_i2^i\]
无符号数所能表示的值的范围
[0 0 …… 0] 到 [1 1 …… 1]即
\[UMax_w = \sum_{i=0}^{w-1}2^i = 2^w-1\]
无符号编码的惟一性
函数B2U是一个双射,将每个长度为w的位向量,映射为0~2^w-1之间的惟一一个值,这种映射是一一对应的关系,便可以反向操做。
补码编码
最多见的有符号数的计算机表示方式就是补码形式,这种形式下,将字的最高有效位解释为负权。
对于向量 \[ \vec{x} = [x_{w-1},x_{w-2},\cdots,x_0] \] 有
\[B2T_w (\vec{x}) = -x_{w-1}2^{w-1} + \sum_{i=0}^{w-1}x_i2^i\]
最高有效位称为符号位,符号位为1时,表示值为负数;符号值为0时,值为非负。
它能表示的最小值是[1 0 …… 0] 其整数值为 \[TMin_w = -2^{w-1} \]
最大值为[0 1 …… 1] 其整数值为\[TMax_w = \sum_{i=0}^{w-1}2^i = 2^w-1\]
强制类型转换的结果保持位不变,只是改变了解释这些位的方式。处理一样字长的有符号数和无符号数之间的转换通常规则是:数值可能会改变,可是位模式不变
补码转换为无符号数
对知足\[TMin_w\leq x \leq TMax_w \]的x有:
\[T2U_w(x) =\begin{cases} x+2^w & x <0 \\\ x & x \geq 0 \end{cases}\]
从以上表达式能够看出,将一个有符号数转为它相应的无符号数时,负数就被转换成了大的整数,非负数则会保持不变。
对知足\[0 \leq u \leq UMax_w \]的x有:
\[U2T_w(u) =\begin{cases} u & x \leq TMax_w \\\ u-2^w & u>TMax_w \end{cases}\]
从以上表达式能够看出,讲一个无符号数转换为补码时,U2T把大于2^w-1的数转化成了负数。
从上述两个公式能够看出,对于在范围\[ 0 \leq x \leq TMax_w \]的范围内的数字有着相同的补码和无符号数表示。对于这个范围之外的数须要加上或者减去2^w
令\[\vec{x} = [x_{w-1},x_{w-2},\cdots,x_0]\] 现截断该位向量k位的结果是\[x' = x mod 2^k\]
当x+y的结果s小于x或者小于y的时候,能够断定无符号数的加法出现了溢出。
模数加法造成了一个阿贝尔群,对于每一个x值一定有有一个加法逆元。
对于知足\[ 0 \leq x <2^w \]的任意x值,其无符号加法逆元为
\[- x =\begin{cases} x & x=0 \\\ 2^w-x & x>0 \end{cases}\]
补码加法
对于知足\[-2^{w-1} \leq x,y \leq 2^{w-1}-1 \]的整数x和y 有
\[x + y =\begin{cases} x+y-2^w & 2^{w-1} \leq x+y & 正溢出 \\\ x+y & -2^{w-1} \leq x+y <2^{w-1} &正常\\\ x+y+2^w & x+y<-2^{w-1} & 负溢出 \end{cases}\]
补码的非
对于知足\[ TMin\_w \leq x <TMin\_w \]的任意x值,其补码的非为
\[- x =\begin{cases} TMin\_w & x=TMin\_w \\\ -x & x>TMin\_w \end{cases}\]
无符号和补码乘法
将一个数截断w就等价于计算该值的模2^w
对于无符号和补码乘法来讲,乘法运算的位级表示都是同样的。
乘以常数
因为在大多数机器上,整数乘法的指令须要10个或者更多的时钟周期,其余整数运算只须要1个时钟周期。编译器使用了优化,试着用位移和加法的运算组合代替乘以常数因子的乘法。
原理: 设x的位模式为 \([x_{w-1},x_{w-2},\cdots,x_0]\)表示无符号整数,那么对于任何$k \leq 0 $都认为 \([x_{w-1},x_{w-2},\cdots,x_0,0,0,\cdots,0]\) 给出了 \(x*2^k\) 的w+k位的无符号表示,右边增长了k个0。
能够看出,左移一个数值至关于执行一个与2的幂相乘的无符号乘法
例如:一个程序包含表达式 x*14 利用 $14 =2^3+2^2+2^1 $ 能够将该乘法重写(x<<3)+(x<<2)+(x<<1),将一个乘法替换为位移和两个加法。
或者利用 $14 =2^4-2^1 $ 重写成 (x<<4)-(x<<1)
二进制小数
表示方法:$ b_m b_{m-1} \cdots b_1 b_0.b_{-1} b_{-2} \cdots b_{-n} $
这个表达描述的定义以下:
\[b = \sum_{i=-n}^{m}2^i*d_i \]
【注】浮点运算只由有限的范围和精度,而且不遵照结合律。
本章重点在于用数学公式准肯定义出计算机中使用的几种数据类型,内容不少,须要好好总结和复习。经过直接操做数字级的位表示,获得了几种算数运算的方式。针对不一样的机器,变量类型存储的大小也不一样、存储方式不一样,为了能使编写的程序在所有范围内正确工做,能够实现跨越不一样的机器、操做系统和编译器的组合,对于这种数学原理的学习是十分重要的。 第二章主要从信息存储的方式、整数表的方法(无符号编码、补码编码)以及相关操做、整数运算(无符号运算、补码运算)、浮点数(两种表示方式)等方面介绍了数据的存储表示方式,进行计算的结果等内容。