Linux系统学习笔记:信息的表示

来源:互联网 发布:软件产品与软件服务 编辑:程序博客网 时间:2024/06/05 19:57

计算机采用二值信号来表示信息,这些二进制的数字称为位。计算机的表示法中数字的位数是有限的,结果太大无法表示时,运算会溢出。计算机有自己的一套整数和浮点数的表示和运算法则,这和现实中的十进制运算是有很大不同的。本篇就来看一下信息在计算机中的表示方法。

Contents

  • 信息存储
  • 整数
    • 整数运算
  • 浮点数

信息存储

计算机以字节作为最小的可寻址的存储器单位。存储器被视作一个大的字节数组,称为虚拟存储器,每个字节由一个唯一的数字标识,称为它的地址,所有地址的集合称为虚拟地址空间。

1个字节有8位,在二进制中值域为 00000000 ~ 11111111 ,十进制的值域为0 ~ 255,十六进制的值域为 00FF 。一般为了方便,以十六进制表示字节的值。

计算机中用字长来指明整数和指针的标称大小,虚拟地址以字来编码,所以字长决定了虚拟地址空间的最大大小。字长为32位的计算机的虚拟地址空间最大为4GB,现在64位的机器也很常见了。

在C语言篇已经给出了不同数据类型的存储大小,这里复述一下。下表是C数据类型典型的字节大小(表中还给出了32位的Intel数据类型和GAS后缀):

C数据类型Intel数据类型GAS后缀32位64位char字节b11shortw22int双字l44unsigned int双字l44long双字l48unsigned long双字l48char *双字l48float单精度s44double双精度l88long double扩展精度t10/1210/12

多字节的对象会被存储为连续的字节序列,对象的地址为字节序列中最小的地址。多字节对象的字节序列也存在一个顺序,在存储器中从最低有效字节到最高有效字节存储的方式称为小端法,从最高有效字节到最低有效字节存储的方式称为大端法。这种字节顺序是处理器芯片决定的。

字符串表示为字符的数组,因此它的存储和字节顺序无关。

例, int 值为 0x01234567 ,位于地址 0x100 处:

大端法:        0x100  0x101  0x102  0x103──────┬──────┬──────┬──────┬──────┬──────  ... │  01  │  23  │  45  │  67  │ ...──────┴──────┴──────┴──────┴──────┴──────小端法:        0x100  0x101  0x102  0x103──────┬──────┬──────┬──────┬──────┬──────  ... │  67  │  45  │  23  │  01  │ ...──────┴──────┴──────┴──────┴──────┴──────

涉及到字节顺序的情况主要有三种:

  • 网络程序,它可能在不同字节顺序的机器间传输数据。
  • 查看机器级程序,读机器代码时常常会碰到这种情况。
  • 规避正常类型系统的程序,使用强制类型转换来以不同的类型引用对象。

代码的表示取决于机器的指令和编码方式,不同的机器一般是不兼容的。

整数

C语言有多种整型数据类型,在前面和C语言篇已经总结过了。对于无符号整型,取值范围为 02n1,有符号整型的取值范围为 2n12n11 (C语言保证的范围是 (2n11)2n11), n 为对应的位数。

有 w 位的整型数 x ,写作[xw1xw2, ..., x0]表示每一位。

无符号整数的值为

B2Uw(x)=i=0w1xi2i

这样 B2Uw 就定义了一个双向映射 B2Uw:{0,1}w{0,...,2w1} 。最小值 UMinw=0,用[00...0]表示,最大值 UMaxw=2w1 ,用[11...1]表示。

有符号整数用二进制补码表示,它将字的最高有效位解释为负权,有符号整数的值为

B2Tw(x)=xw12w1+i=0w2xi2i

最高有效位称为符号位,设为1时为负数,设为0时为非负数。 B2Tw 也定义了一个双向映射 B2Tw:{0,1}w{2w1,...,2w11} 。最小值 TMinw=2w1 ,用[10...0]表示,最大值 UMaxw=2w11 ,用[01...1]表示。

几乎所有的机器都用二进制补码表示有符号整数。为保证可移植性,应该使用C标准库中 <limits.h> 定义的 UINT_MAX 、 INT_MIN 、 INT_MAX 。

无符号数和二进制补码之间的转换关系为

T2Uw(x)=B2Uw(T2Bw(x))=x+xw12w={x+2w,x,x<0x0

U2Tw(x)=B2Tw(U2Bw(x))=xxw12w={x,x2w,x<2w1x2w1

注意C中表达式若同时有有符号数和无符号数,会提升为无符号数进行运算,如 -1 > 0U 为真。

/media/note/2012/03/13/linux-info-repr/fig1.png

无符号数和二进制补码之间的转换

整数从较小数据类型转换为较大数据类型称为扩展。对于无符号数,在表示的开头加0,称为零扩展;对于有符号数,在表示的开头加最高有效位的值,称为符号扩展。扩展可以保证值不变。

整数从较大数据类型转换为较小数据类型称为截断。截断简单地抛弃高位。对于无符号数,截断后的值为原值取 mod2k ;对于有符号数,截断先将原值取 mod2k ,再转换为有符号数。

整数运算

大部分的编程语言支持固定精度的运算。这可能导致计算结果溢出,即结果超出了数据类型的字长限制。

无符号运算可以视为模运算。对于 w 位的无符号整型数 x 和 y ,无符号之和和加法逆元为

x+uwy=(x+y)mod2w={x+y,x+y2w,x+y<2w2wx+y<2w+1

uwx={x,2wx,x=0x>0

无符号乘积为

xuwy=(xy)mod2w

两个数的二进制补码运算和无符号运算有相同的位级表示,有

x+twy=U2Tw((x+y)mod2w)=x+y+2w,x+y,x+y2w,x+y<2w12w1x+y<2w1x+y2w1

twx={2w1,x,x=2w1x>2w1

xtwy=U2Tw((xy)mod2w)

一个求二进制补码的加法逆元的技巧是 -x = ~x + 1 。

/media/note/2012/03/13/linux-info-repr/fig2.png

无符号和二进制补码的加法

整数加减法、移位和位运算只需1个时钟周期,通常乘除法指令要慢得多(现在已经比以前好些了),因此常用加法和移位运算的组合来尝试代替它们。

对于无符号和二进制补码都有 x << k 等价于 x2k 。

对于无符号有 x >> k 等价于 x/2k ,对于二进制补码有 (x<0 ? (x+(1<<k)-1) : x) >> k 等价于 x/2k。这里 >> k 分别为逻辑右移和算术右移。表达式的差异来自于整数除法的舍入,整数除法舍入到0。

浮点数

目前所有的机器都支持IEEE浮点标准。IEEE浮点标准用 V=(1)sM2E 形式来表示一个数。符号 s 由一个单独的符号位 s 编码, s=1 表示为负数, s=0 表示为正数,对数值0的符号位解释做特殊处理。指数 E 由 k 位指数域exp=ek1...e1e0 编码,它是2的幂,对浮点数加权。有效数 M 由 n 位小数域frac=fn1...f1f0 编码,是一个二进制小数,范围在 12ϵ 之间或 01ϵ 之间。

单精度浮点格式中, k=8 , n=23 ,总长32位。双精度浮点格式中, k=11 , n=52 ,总长64位。

值有三种情况:

  • 规格化值:exp的位不是全0和全1。这时指数的值为 E=eBias ,e 为exp的无符号值, Bias=2k11 ,可知指数的范围为 22k12k11 。有效数的值为 M=1+f, f 的二进制表示为0.fn1...f1f0 ,因此 1M<2 。
  • 非规格化值:exp的位全为0。这时 E=1Bias=2k1 , M=f , 0M<1 。
  • 特殊数值:exp的位全为1。小数域全为0时,表示无穷, s=1 为  , s=0 为 + 。无穷用来表示计算溢出。小数域非0时,表示NaN,可用来表示非法运算或未初始化值。

从数轴上看,IEEE浮点数越靠近0越密集,反之越稀疏,绝对值 <1 为非规格化值,绝对值 1 为规格化值,存在两个0值。

从位模式上看,如果把浮点数的位解释为无符号数,它恰好是升序排列的,负浮点数相反。

整数值为0或规格化值,把非0正整数值转换为浮点数,可以将它的二进制表示去掉最高有效位,剩余的位数即为指数的值,加 Bias 得到exp,同时剩余的位左移添0至 n 位得到frac,最后符号位置0。

IEEE浮点数的精度是有限的,标准定义了四种舍入方式:向偶数舍入、向0舍入、向下舍入和向上舍入。

链接: http://www.yeolar.com/note/2012/03/13/linux-info-repr/
原创粉丝点击