计算机系统-信息的表示与处理
发表于:2022-11-10 |
字数统计: 3.4k | 阅读时长: 11分钟 | 阅读量:

信息的表示与处理

信息的表示

二进制、八进制、十进制、十六进制。基数不同,只重位置,不看具体的值。

字长(指针的大小)

虚拟地址以此来编码,一般的高位机向后兼容。

计算机与编译器都支持多种的编码

无符号整数与有符号整数的区别在c中,关键字unsigned注明了无符号整数。

寻址与字节顺序

一般的,多字节对象连续存址。

机器之中排列字节地址有差异,有的以最低有效字节在前面——小端法,有的以最高有效字节在前面——大端法。

字符串表示:一般的字符串被编码以null结尾的字符数组,每个字符使用某种编码表示,例如ASCII编码。

布尔代数 0,1

布尔代数相关运算:与、或、非、异或。

布尔与:同位为1结果即为1,否则为0。

布尔或:同位有1结果即为1,否则为0。

布尔非:1为0,0为1。

布尔异或:同位为1但不同时为1为1,否则为0。

布尔代数—布尔环(w位向量上的与或非运算时的新形式)

位向量还可以用来表示掩码,i位为1时代表有效使能,为0则为无效使能。

C语言很号的支持按位布尔

位级运算实现掩码运算很好,这里的掩码表示一个位模式,表示一个字节中有效的位的集合。

逻辑运算

逻辑或、与、非。

非零的参数表示为TRUE,为0的表示为FALSE。

逻辑运算存在短路特性。

移位运算 向左或向右移动位模式

x << k 左移k位,丢弃最高的k位,在右端补齐k个0。

x >> k 右移k位,但是区分逻辑左移与算数左移的区分,对于逻辑右移,在左端补齐k个0,对于算数右移,需要补齐最高有效位,可能是1。

C没有规定有符号数应该使用哪一种右移,但是几乎所有的编译器都对有符号数采用算数右移,对于无符号数,右移必须是逻辑的。

在Java里,>>> 表示逻辑右移,>>表示算数右移。

优先级问题,移位的运算优先级低于加减法。

编码整数的方式又两种,一种只能表示非负数,一种都可以表示。

C中有多种数据类型,都可以表示整数:

CHAR、SHORT、INT、LONG(UNSIGNED)

他们表示的字节大小各不相同,一般的取决于字长,例如在32位机中,long只占4个字节。

无符号编码具有重要意义,因为这是一个双射。

原码、反码、补码

最高位为符号位,0表示正数,1表示负数。

正数的反码是自身,负数的反码是除符号位之外,全部取反。

正数的补码也是自身,负数的补码是反码+1

补码编码

补码:反码加一”只是补码所具有的一个性质,不能被定义成补码。负数的补码,是能够和其相反数相加通过溢出从而使计算机内计算结果变为0的二进制码。

用补码表示负数,在补码的定义之中,字的有效最高位解释为负权,因此最高位为1时,表示该数为负数。

对于补码而言,这也是一个双射,补码编码同样具有唯一性。

C语言标准之中没有要求使用补码来表示,有符号整数,但是几乎所有的机器都是使用补码的。

除却补码之外,原码与反码也能表示有符号整数。

原码、反码都以最高位为符号位,不同的是,反码符号位取非。

有符号数与无符号数之间转换
对C来说,类型的转换从不关心具体的数,对于这个问题,C是从位级角度来考虑的。

一般的,对于强制类型转换,位的值不发生改变,只改变位的位置。

零扩展

从较小的类型转换为较大类型时,在开头扩展0。

位截断

丢弃高位,可能会造成溢出。

有符号数到无符号数的隐式转换,会导致错误或者漏洞,杜绝的方式试试禁用无符号数。

例如:一种类型的表达式被赋值给另外一种类型的变量时,转换就是隐式的。

C语言中同时包含了对有符号和无符号数表达式的处理方式,当同时出现两种数时,C会隐式的强转为无符号数,例如在<,>运算中,结果就会很直观。

运算

无符号加法

考虑两个w位的无符号数相加,他们的和的范围应该在0到w+1位之间。

但是C不允许这样的扩张出现,因此必须使用过位截断,使得他们的和在0到w位之间。截断时,截断高位。

在C中,不会将溢出作为错误而返回信号。

溢出时,不难发现,结果等于两数之和与2

的w次方的模数。

补码加法

对于补码的加法,必须确定当结果太大(为正)或太小(为负)时,应该怎么做。

补码,最高位是符号位,表示负权。因此两个数的范围在-2w-1到2w-1之间。这意味着,要想表示两个数的和,需要w+1位。(符号位在内)

结果是截断到w位。

值得一提的是,两个数的w位补码之和和无符号数之和有完全相同的位级表示。

无符号乘法

对于两数乘积的取值范围,需要2w位来表示,明显的C语言不可能允许这样的大小扩张,最终结果依旧需要w位,而将无符号数截断为w位等价于计算该值取模2的w次方。

补码乘法

对于补码乘法,C语言的有符号乘法通过截断为w位来实现,将一个补码截断为w位,相当于先计算该值模2的w次方,再把无符号数转换为补码。

一般的,对于无符号和补码乘法来说,乘法运算结果的位级表示都是一样的。

例如:

(101) * (011) = (001111) = (111)【截断后的】

无符号数表示:5 * 3 = 7

(101) * (011) = (110111) = (111)【截断后的】

补码表示:-1 * 3 = -1

虽然完整的乘积的位级的表示可能不同,但是截断后乘积的位级表示是相同的。

乘以常数

因为,在大多数机器上,整数乘法指令相当的慢,需要10个或更多时钟周期,因此编译器进行了一项优化,试着用移位加加法运算的组合来代替乘以常数因子的乘法。

考虑乘以2的幂的情况,再推广至全体常数。

可以发现左移一个数值等价于执行一个与2的幂相乘的无符号乘法。固定大小的补码算数运算的位级操作与其无符号运算等价。

但是无论是无符号还是补码,乘以2的幂都会导致溢出,结果说明,即使溢出,通过移位得到的结果也是一样的。

除以2的幂

在大多数机器上,整数除法比整数乘法更慢,需要30或者更多的时钟周期。

除以2的幂,也可以用移位运算来实现,只不过使用的是右移,无符号数和补码分别使用逻辑移位和算术移位来达到目的。

整数除法总是舍入到0,它将向下舍入到一个正值,向下舍入到一个负值。

对于无符号运算右移很简单,一部分原因是因为无符号的右移一定是逻辑的。

c >> k产生的结果是 c / 2的k次方。

对于除以2的幂的补码运算来说,情况稍微要复杂一些,因为要保证负数依然为负,移位要执行的算数移位。

除以2的幂的补码除法,向下舍入
变量x和k分别有补码值x和无符号数值k,且0≤k<w,则当执行算术移位时,C表达式x>>k产生数值 x /2^k。

对于非负数来说,最高位是0,因此算数右移k位与除以2^k是一样的。

作为负数,如果出现舍入的情况时,移位导致结果向下舍入,此时就需要调整策略。

作为一个负数,算数右移后的位向量刚好就是就w-k位表示的补码数从w-k位符号扩展到w位。通过在移位之前,偏置这个值,来修正不合适的舍入。

思考

计算机执行的“整数”运算实际上是一种模运算形式。

表示数字的有限字长限制了可能的值的取值范围,结果运算可能溢出。

补码表示提供了一种既能表示负数也能表示正数的灵活方法,同时使用了与执行无符号算术相同的位级实现,这些运算包括像加法、减法、乘法,甚至除法,无论运算数是以无符号形式还是以补码形式表示的,都有完全一样或者非常类似的位级行为。

浮点数

浮点表示对形如

的有理数进行编码。它对执行涉及非常大的数字非常接近于0的数字,以及更普遍地作为实数运算的近似值的计算,是很有用的。

一般的,IEEE浮点标准被几乎所有的计算机支持。

二进制小数

IEEE浮点表示

IEEE浮点标准用

的形式来表示一个数:
符号(sign),s决定这数是负数(s=1)还是正数( s=0),而对于数值0的符号位解释作为特殊情况处理。
尾数(significand)M是一个二进制小数。

阶码(exponent)E的作用是对浮点数加权,这个权重是2的E次幂(可能是负数)。

标准浮点格式

规格化

当exp的位模式不全为0,也不全为1时,都是规格化的。

阶码的值是E = e - 偏置值。

e是无符号数,偏置值为2的k-1次方-1,对于单精度是-126到127

小数字段frac被描述为小数值f,f在0到1之间。尾数的定义是M = 1+f。这种表示方法,假设没有一处,尾数在1到2之间,那么就能轻松额外获得一个精度位,既然第一位总是等于1,那么就不需要显示的表示它。

非规格化

当阶码全为0的时候,表示的书就是非规格化的。

阶码为E = 1 - 偏置,尾数M = f,也就是小数的值,不包含隐含的开头1。

非规格化数可以表示0,因为对于M来说,必须大于或等于1.因此不能表示0,事实上对于0的位模式,阶码字段与小数域全为0。

但是-0与+0在符号位上是有差异的,在IEEE中,在某些方面,他们被认为是不同的。

特殊值

当阶码全为1时,就会出现无穷的表示。

舍入

因为表示方法限制了浮点数的范围和精度,所有浮点运算只能近似的表示实数运算。

一般的,为了找到一个最接近的匹配值,可以用期望的浮点形式表示出来,这就是舍入。

浮点运算

IEEE标准指定了一个简单的规则,来确定加法和乘法这样的算术运算的结果。

C语言中的浮点数

C语言中提供了两种不同的浮点数据类型,float和double,在支持IEEE浮点格式的机器上,这些数据类型对应单精度和双精度浮点,另外这类机器采用偶数舍入的舍入方式。

当在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为整数不确定(integer indefinite)值。一个从浮点数到整数的转换,如果不能为该浮点数找到一个合理的整数近似值,就会产生这样一个值。因此,表达式(int)+1e10会得到-21483648,即从一个正值变成了一个负值。

上一篇:
变治法
下一篇:
Oracle19C+PLSQL安装和配置详细教程