信息的表示与存储

第二章 信息的表示与处理

目录

第二章 信息的表示与处理

2.1  信息存储

2.1.1  字数据大小

2.1.2  寻址和字节顺序

2.1.3  表示字符串

2.1.4  位运算符(布尔代数)

2.1.5  逻辑运算

2.2  整数表示

2.2.1  无符号数以及补码编码

2.2.2  有符号数和无符号数的转换

2.2.3  补码的非

2.2.4  乘以常数

2.2.5  除以2的幂

2.2.6  浮点数

 

 

2.1  信息存储

整数的表示范围比浮点数小,但是数值准确无误差。浮点数由于阶码的存在,表示的范围较大,但是由于尾数的位数有限会存在精度误差。

程序以字节(8 bite)为单位编址。机器级程序将内存看作一个非常的大的字节数组,在数组中存储所有信息。

2.1.1  字数据大小

字长,一个存储单元的位长度,决定了虚拟地址空间大小。指针型变量用全字长来存储。字长为w,地址空间的最大值为2w-1字节。

“64位程序”和“32位程序”区别不在于运行程序的机器类型,而是该程序是如何编译的。比如,数据类型long在32位程序中占据4字节,在64位程序中占据8字节。int类型数据在64位和32位系统中通常都占用4字节。为了提升程序可移植性,将数据类型大小固定,不随编译器和机器设置变化,类型int32_t 和类型int64_t 表示占用4字节和8字节。类型size_t表示C语言中可以达到的最大长度,是表示某一数据结构大小的首选类型。

2.1.2  寻址和字节顺序

对于跨越多字节的程序对象,地址采用所使用的字节中最小的地址。程序对象在多字节中的存储顺序分为大端法和小端法。例:

有一int型变量x,地址为0x100,十六进制值为0x01234567,不同机器中x的存储形式:

 

十六进制数值:0x01234567
虚拟地址空间地址:0x100     0x101     0x102     0x103
  大端法机器存储:   01        23        45        67
  小端法机器存储:   67        45        23        01

 

此外注意,大多数Intel兼容机都只用小端模式。

2.1.3  表示字符串

C语言中字符串字符用ASC||码表示,并且自动在末尾补上null(值为0)字符。规律:十进制数值a(1 ~ 9)用ASC||码表示为0x3a;字母‘a’ ~ ‘z’的ASC||码为0x61 ~ 0x7A。

同样的文本代码,在使用ASC||码作为字符码的任意系统都可以得到相同的结果。但是对二进制代码,在不同的系统中即使是相同的进程也有不一样的二进制码,不同机器类型使用不同的不兼容的指令和编码方式。因此,文本程序比二进制程序有更好的平台独立性和移植性。

对于计算机系统而言,从机器的角度来看,程序仅仅是一个个的字节序列,按此序列机器执行相应的动作。机器没有关于源程序的任何信息。

2.1.4  位运算符(布尔代数)

&、| 位运算符符合分配律。假设a,b,c是三个位向量。a | (b & c) =(a | b)&(a | c),a & (b | c) = (a & b) | (a & c)。

^异或位运算符。假设a, b, c是三个位向量,则a ^ a = 0;则a ^ b = c,则 c ^ a = b,c ^ b = a,(a ^ b)^ a = b。

~ 位运算符。~a + a = -1(该公式中位向量看作补码,并转换为十进制数)

<<、>>位运算符。移位时连同符号位一起进行。左移<<对空闲位补0;右移>>,若为逻辑右移,空闲位补0,若为算术右移,空闲位数值与符号位相同。但是实际上,几乎所有的编译器/机器组合都对有符号数进行算数右移。

C语言中的位级运算,先把数字换算为二进制数。

2.1.5  逻辑运算

逻辑运算符相对于位运算符是成对出现的,结果只能为0x00(false)或0x01(true)。在逻辑运算中,如果只对第一个参数求值就可以确定表达式结果,则不对第二个参数求值。例如,表达式 a && 5/a不会造成被0除的可能。

2.2  整数表示

2.2.1  无符号数以及补码编码

无符号编码以及补码编码都具有唯一性,可以区分出原码+0和-0的不同。补码的表示范围是不对称的| TMin | = | TMax | + 1,补码所有位都是1时表示十进制数字-1。

补码的出现使减法运算可以当作加法运算,a – b可以看做 a + (-b),在上述表达式中,-b的补码就是将其二进制原码变换成一个无符号的二进制数,使该无符号二进制数 + a的结果与a – b的结果等同。类似于钟表指针,起初指针在0(12)刻度,指针逆时针旋转x个刻度的效果与顺时针旋转12 – x个刻度的效果相同,12是钟表刻度的模,二进制码的模则取决于二进制数存储的位长,负数原码 + 负数补码 = mod。 例如:

正数的补码为本身,无意义,此处只考虑负数的补码。

 

 

 图2.1  负数补码示例

如图可得:互为补码的两个二进制码,必然对应一正一负的一组十进制数,使其绝对值的和为二进制码的mod。正数对应被转换的无符号补码,负数对应有符号的原码。

2.2.2  有符号数和无符号数的转换

强制类型转换并没有改变变量在内存中的二进制位值,只是改变了解释二进制位值的方式。就像上图2.1中1011一样,将其按照原码解释就是一个负数,值为-3,将其按照补码解释就是一个无符号正数,对应的原值为-5。

变量在强制转换为一个更大的数据类型时,无符号数在高位补0,补码在高位补符号位。变量若转换为一个更小的数据类型,则保留低位位值,高位连同符号位一起截去。

将short类型转换为unsigned类型时,先改变其占位大小进行位扩展,再将其的解释方式改成无符号型。

计算机中数值的存储处理都是以二进制进行的,自然界现实生活中是以十进制计数的,在分析计算机内部过程的时候,以十六进制表示比较方便。处理问题时要做好对应关系,二进制是怎样进行的,这个过程十六进制如何表示,对应的十进制数又有何特征。

涉及到比大小的情况不要用无符号类型(size_t,unsigned),因为无符号类型永远大于等于0并且比大小时还会将有符号数隐式转换为无符号数。

2.2.3  补码的非

在二进制视角下:补码x若为TMinw,则补码的非-twx为(mod – x),即所有位值(包括符号位)取反再末位加1。

例如:

 

 

 图2.2  补码的非

注意:补码的非仍然是补码,仍需按照补码规则才能还原为原码以及原码的十进制。补码以及补码的非对应的原码十进制数互为相反数,对应的二进制为所有位值取反加1。(原码转换补码为符号位不变,数值位取反加1。)

2.2.4  乘以常数

运行乘法的时候,编译器会进行优化以提高效率。若乘数的二进制形式中,

位值0比较多,则可以简化为形式A:(x << n) + (x << (n - 1)) + (x << (n - 2)) + … +( x << m)    例如:乘数1110 = 1000 + 0100 + 0010

位值1比较多,则可以简化为形式B:(x << (n + 1))- (x << m)  
例如:乘数 1110 = 1,0000 – 0010

2.2.5  除以2的幂

对于无符号数x,右移k位x >> k相当于x/2w向下取整,右移k位并且(x + (1 << k) - 1)>> k相当于向上取整。十进制除法运算规则为向0取整。所以,除法 补码/2k 的运算规则C语言描述为:(x < 0 ?  x + (1 << k) – 1 : x)>> k
说明:负数的补码需要向上取整是因为,向上取整使无符号补码的十进制数值变大,所以其对应的有符号原码十进制数的绝对值变小,从而实现向零取整。

2.2.6  浮点数

通用的IEEE浮点标准用V=(-1)s × M × 2E 来表示一个浮点数。s,符号位;M,尾数,决定了精度;E,阶码,决定了表示范围。

浮点数进行加法运算的时候要先对阶(小阶向大阶对齐),所以当两个阶码相差太大的数做加法运算时,小阶码的位值可能会丢失使结果更加的不准确。

posted @ 2020-09-27 21:16  橘子葡萄火龙果  阅读(373)  评论(0编辑  收藏  举报