信息的表示和处理
 
最重要的数字表示:
无符号(unsigned)编码基于传统的二进制表示法,表示
大于或者等于零的数字。
补码(two’s-complement)编码是表示有符号整数的最常见的方式,有 符号整数就是可以为正或者为负的数字。
浮点数(floating-point)编码是表示实数的科学记数法 的以二为基数的版本。
 
信息存储:
机器级程序将存储器视为一个非常大的字节数组, 称为虚拟存储器(virtual memory)。
存储器的每个字节都由 一个唯一的数字来标识,称为它的地址(address),所有可 
能地址的集合称为虚拟地址空间(virtual address space)
 
程序对象(program object),即程序数据、指令和控制信息
 
指针也有两个方面:值和类型。它的值表示某个对象的位置,而它的类型表示那个位置
上所存储对象的类型(比如整数或者浮点数)。
 
十六进制表示法
一个字节由8 位组成。
在二进制表示法中,它的值域是000000002 ~ 111111112 ;
如果用十 进制整数表示,它的值域就是010 ~ 25510。
用十六进制书写,一个字节的值域为0016 ~ FF16。
 
字长(word size),指明整数和指针数据的标称大小(nominal size)
“char”是由于它被用来存储文本串中的单个字符这一事实而得名,但它也能用来存储整数值。
ISO C99 引入的“长长”整 数数据类型允许64 位整数。对于32 位机器来说,编译器必须把这种数据类型的操作编译成执行 
一系列32 位操作的代码。(64位机 :gcc -m32 生成32位的代码)
 
 
寻址和字节顺序
一种规则—最低有效字节在最前面的方式,称为小端法(little endian)。大多数Intel 兼容机都
采用这种规则。后一种规则—最高有效字节在最前面的方式,称为大端法(big endian)。
 
 
布尔代数简介:
布尔运算~ 对应于逻辑运算NOT,在命题逻辑中用符号﹁表示。也就是说,当P
不是真的时候,我们就说﹁ P 是真的,反之亦然。相应地,当P 等于0 时,~P 等于1,反之亦
然。布尔运算& 对应于逻辑运算AND,在命题逻辑中用符号∧表示。当P 和Q 都为真时,我们说
P ∧ Q 为真。相应地,只有当p =1 且q =1 时,p & q 才等于1。布尔运算|对应于逻辑运算OR,在
命题逻辑中用符号∨表示。当P 或者Q 为真时,我们说P ∨ Q 成立。相应地,当p =1 或者q =1 时,
p | q 等于1。布尔运算^ 对应于逻辑运算异或,在命题逻辑中用符号(圈里面有个加号你懂的)表示。
 
 
c语言中的逻辑运算
逻辑运算符&& 和 || 与它们对应的位级运算& 和 | 之间第二个重要的区别是,如果对第一个
参数求值就能确定表达式的结果,那么逻辑运算符就不会对第二个参数求值。
 
 
C 语言中的移位运算
C 语言标准并没有明确定义应该使用哪种类型的右移。对于无符号数据(也就是以限定词
unsigned 声明的整型对象),右移必须是逻辑的
x<<k:左移k位。X>>k:右移
 
整数表示:
值得注意的特点是取值范围不是对称的—负数的范围比整数的范围 大1
 
 
数据类型long long 是在ISO C99 中引入的,它需要至少8 个字节 表示。 (gcc -std=c99
 
*C 和C++ 都支持有符号(默认)和无符号数。Java 只支持有符号数。
 
 
无符号数的二进制表示有一个很重要的属性,就是每个介于0 ~ 2w-1 之间的数都有唯一一
个w 位的值编码。
 
 
补码编码
最常见的有符号数的计算机表示方式是补码表示形式。在定义中,字的最高有效位解释为负权,使用函数B2T
同无符号表示一样,在可表示的取值范围内的每个数字都
有一个唯一的w 位的补码编码。用数学语言来说就是B2Tw 是一个双射—每个长度为w 的位向
量都对应一个唯一的值;反过来,每个介于-2w-1 和2w-1-1 之间的整数都有一个唯一的长度为w
的位向量二进制表示。
 
 
补码的范围是不对称 的:|TMin| = |TMax| + 1,也就是说,TMin 没有与之对应的正数。
。之所以会有这样的不对称性,是
因为一半的位模式(符号位设置为1 的数)表示负数,而一半的数(符号位设置为0 的数)表示非负数。
因为0 是非负数,也就意味着能表示的正数比负数少一个。第二,最大的无符号数值刚
好比补码的最大值的两倍大一点:UMaxw = 2 TMaxw + 1。
 
 
有符号数和无符号数之间的转换
c语言中支持不同数字类型的强制性转换。
处理同样字长的有符号数和无符号数之间的互相转换的一般规则是:数值可能会改变,但位模式不变
当将一个有符号数映射为它相应的无符号 数时,负数就被转换成了大的正数,而非负数会保持不变。
 
 
无符号与补码表示之间互相转换的结果。对于在0 ≤ x < 2w-1 范围之内
的值x 而言,我们得到T2Uw (x) = x 和U2Tw (x) = x。也就是说,在这个范围内的数字有相同的
无符号和补码表示。对于这个范围以外的数值,转换需要加上或者减去2w。
 
 
C 语言中的有符号数与无符号数
尽管C 语言 标准没有指定有符号数要采用某种表示,但是几乎所有的机器都使用补码。通常,大多数数字都 
默认为是有符号的。要创建一个无符号常量,必须加上后缀字符‘U’或者‘u’。
 
C 语言允许无符号数和有符号数之间的转换。转换的原则是底层的位表示保持不变。
 
扩展一个数字的位展示
将一个无符号数转换为一个更大的数据类型,我们只 需要简单地在表示的开头添加0,这种运算称为零扩展(zero extension)。
将一个补码数字转换 为一个更大的数据类型可以执行符号扩展(sign extension),规则是在表示中添加最高有效位的 
值的副本
 
截断数字
    截断一个数字可能会改变其值,这也是值溢出的一种形式。
    对于一个值为x的无符号数,将其截断成k位,结果等于以2的k次方为模对x取模。
    对于一个值为x的有符号数,有类戏的结论——模运算的结果也按照有符号数来解析
 
整数运算
 
溢出:完整整数结果不能放到数据类型的字长限制中去。
 
 判断无符号运算是否溢出,例如s=x+y(s、x、y均为无符号数),则唯一可靠的判断标准就是s<x或s<y。
 
补码非的位级表示:
求位级补码非的第一种方式是对每一位求补,再对结果加1
第二种方式:建立在将位向量分为两部分的基础之上的。假设k 是
最右边的1 的位置,因而x 的位级表示形如[xw-1, xw-2,…, xk+1, 1, 0,…, 0]。(只要x ≠ 0 就能够找
到这样的k。)这个值的非写成二进制格式就是[~xw-1, ~xw-2,…, ~xk+1, 1, 0,…, 0]。也就是,我们对
位位置k 左边的所有位取反。
 
IEEE 浮点标准用V = (-1)s × M × 2E 的形式来表示一个数:
• 符号(sign) s 决定这个数是负数(s=1)还是正数(s=0),而对于数值0 的符号位解释作
为特殊情况处理。
• 尾数(significand) M 是一个二进制小数,它的范围是1 ~ 2-ε,或者是0 ~ 1-ε。
• 阶码(exponent) E 的作用是对浮点数加权,这个权重是2 的E 次幂(可能是负数)。
将浮点数的位表示划分为三个字段,分别对这些值进行编码:
• 一个单独的符号位s 直接编码符号s。
• k 位的阶码字段exp = ek-1…e1e0 编码阶码E。
• n 位小数字段frac = fn-1…f1 f0 编码尾数M,但是编码出来的值也依赖于阶码字段的值是否
等于0。
 
 
在单精度浮点格式(C 语言中的float)中,s、exp 和frac 字段分别为1 位、k = 8 位和n = 23 位,得到一个32 位的表示。 
在双精度浮点格式(C 语言中的double)中,s、exp 和frac 字段分别为1 位、k = 11 位和n = 52 位,得到一个64 位的表示。
 
 
根据exp 的值,被编码的值可以分成三种不同的情况(最后一种情况有两
个变种)
 
情况1 :规格化的值
这是最普遍的情况。当exp 的位模式既不全为0(数值0),也不全为1(单精度数值为255,双精度数值为2047)时,都属于这类情况。
在这种情况中,阶码字段被解释为以偏置 (biased)形式表示的有符号整数。也就是说,阶码的值是E = e-Bias,其中e 是无符号数,其位 
表示为ek-1…e1e0,而Bias 是一个等于2k-1-1(单精度是127,双精度是1023)的偏置值。由此
产生指数的取值范围,对于单精度是-126 ~ +127,而对于双精度是-1022 ~ +1023。
 
情况2 :非规格化的值
当阶码域为全0 时,所表示的数就是非规格化形式。在这种情况下,阶码值是E = 1 - Bias,
而尾数的值是M = f,也就是小数字段的值,不包含隐含的开头的1。
非规格化数有两个用途:
(1)它们提供了一种表示数值0 的方法
(2)表示那些非常接近于0.0 的数。它们提供了一种属性,称为 渐溢出(gradual underflow),其中,可能的数值分布均匀地接近于0.0。
 
情况3 :特殊值
最后一类数值是当指阶码全为1 的时候出现的。当小数域全为0 时,得到的值表示无穷,当
s = 0 时是+ ∞,或者当 s = 1 时是- ∞
 
对于浮点数,需要明白,可以表示的数并不是均匀分布的,在越靠近原点处越稠密。
 
舍入
IEEE 浮点格式定义了四种不同的舍入方式。默认的方 法是找到最接近的匹配,而其他三种可用于计算上界和下界。(向(最近)偶数舍入、向零舍入、向上舍入、向下舍入。)
 
向偶数 舍入(round-to-even),也称为向最接近的值舍入(round-to-nearest),是默认的方式,试图找到 一个最接近的匹配值
向零舍入方式把正数向下舍入,把负数向上舍入,得到值 x^,使得 | x^^ | ≤ | x |。向下舍入方
式把正数和负数都向下舍入,得到值x-,使得x- ≤ x。向上舍入方式把正数和负数都向上舍入,
得到值x+,满足x ≤ x+。
 
浮点运算
IEEE 标准指定了一个简单的规则,用来确定诸如加法和乘法这样的算术运算的结果。把浮
点值x 和y 看成实数,而某个运算⊙定义在实数上,计算将产生Round (x ⊙ y),这是对实际运算
的精确结果进行舍入后的结果。(优势在于,它可以独立于任何具体的硬件或者软 件实现)
 
c语言中的浮点数:
   当在int、float 和double 格式之间进行强制类型转换时,程序改变数值和位模式的原
则如下(假设int 是32 位的):
• 从int 转换成float,数字不会溢出,但是可能被舍入。
• 从int 或float 转换成double, 因为double 有更大的范围( 也就是可表示值的范
围),也有更高的精度(也就是有效位数),所以能够保留精确的数值。
• 从double 转换成float,因为范围要小一些,所以值可能溢出成为+ ∞或- ∞。另外,
由于精确度较小,它还可能被舍入。
• 从float 或者double 转换成int, 值将会向零舍入。例如,1.999 将被转换成1,
而-1.999 将被转换成-1。进一步来说,值可能会溢出。C 语言标准没有对这种情况指
定固定的结果。与Intel 兼容的微处理器指定位模式[10...00](字长为w 时的TMinw)为
整数不确定(integer indefinite)值。一个从浮点数到整数的转换,如果不能为该浮点数
找到一个合理的整数近似值,就会产生这样一个值。因此,表达式(int)+1e10 会得
到-21483648,即从一个正值变成了一个负值。
 
 
    浮点加法具有交换性,但不具有结合性。
    例如,在单精度浮点计算中 表达式((3.14+1e10)-1e10)的值为0.0——因为舍入,值3.14会丢失。另一方面,表达式(3.14+(1e10-1e10))的值为3.14。
    浮点加法不具有结合性,这是缺少的最重要的群属性。
   浮点加法满足单调性属性:如果a>=b ,则对于任意x,除非x等于NaN,都有x+a>=x+b。这一属性是无符号或二进制补码加法所具有的。
 
 
计算机将信息按位编码,通常组织成字节序列。
在相同长度的无符号和有符号整数之间进行强制类型转换时,大多数C 语言实现遵循的原
则是底层的位模式不变。
在补码机器上,对于一个w 位的值,这种行为是由函数T2Uw 和U2Tw
来描述的。
C 语言隐式的强制类型转换会出现许多程序员无法预计的结果,常常导致程序错误。
由于编码的长度有限,与传统整数和实数运算相比,计算机运算具有完全不同的属性。
 
    和大多数其他程序语言一样,C 语言实现的有限整数运算和真实的整数运算相比,有一些特
殊的属性:
    由于溢出,表达式x*x 能够得出负数。但是,无符号数和补码的运算都满足 整数运算的许多其他属性,包括结合律、交换律和分配律。这就允许编译器做很多的优化.我们已经看到了几种使用位级运算和算术运算组合的聪明方法:
(1)使用补码运算, ~x+1 等价于 -x 。
(2)假设我们想要一个形如[0,…,0,1,…,1] 的位模式,由w - k 个 0 后面紧跟着k 个1 组成。这些位模式有助于掩码运算。这种模式能够通过C 表达式(1<<k)-1 生成.
    利用的是这样一个属性,即我们想要的位模式的数值为2k-1。例如,表达式(1<<8)-1 
将产生位模式0xFF。
浮点表示通过将数字编码为x×2y 的形式来近似地表示实数。最常见的浮点表示方式是由
IEEE 标准754 定义的。它提供了几种不同的精度,最常见的是单精度(32 位)和双精度(64
位)。IEEE 浮点也能够表示特殊值+ ∞、- ∞和NaN。
 
    必须非常小心地使用浮点运算,因为浮点运算只有有限的范围和精度
而且不遵守普遍的算 术属性,比如结合性。 
 
 
遇到的问题与总结:
 
非规划值为什么可以均匀接近0:
这里有一个例子:如果全部用十进制表示,对于类似0.0123的浮点数,规格化的表示应为1.23e-2。但对于某些过小的数,如1.23e-130,允许的阶数位数不能满足阶数大小的需要,这时可能就会在尾数前添加前导0,如将其表示为0.000123e-126。
但是非规格化浮点数有争议:可以使任何浮点运算可以在任何浮点数上操作,而不产生下溢出异常,但另一方面它也可能导致更多的除以0错误和NaN的出现。
 
 
这是一份别人对此书的读书摘要 http://www.ithao123.cn/content-563555.html
有阅读,摘写一点