2.整数表示
用位来表示整数有两种不同的方式:1. 表示非负数 2. 表示负数、零、正数
引入一些数学术语
- 整型数据类型
C语言支持多种整型数据类型-------表示有限范围的数。每种类型都能用关键字来指定其大小,这些关键字 包括char、short、long,同时还可以指示被表示的数字是非负数(声明为unsigned),或者可能是负数(默 认)
- 无符号数的编码
-
一个整数数据类型有w位。可以将位向量写成 X,表示整个向量,或者写成[Xw-1,Xw-2,…,X0],表示向 量中的一位。把 X 看做一个二进制表示的数,就获得 X 的无符号表示。用函数B2Uw表示,函数B2Uw是一个双射。
-
原理:无符号编码的定义
对向量 X = [Xw-1,Xw-2,…,X0]:
-
取值范围:
1. 最小值是用位向量[00…0]表示,也就是整数0,
2. 最大值是用位向量[11…1]表示,也就是整数值:
无符号数的二进制表示有一个很重要的属性,也就是介于0~2w-1之间的数都有唯一一个w位的值编码,即无符号数编码的唯一性
-
- 补码编码
- 最常见的有符号数的计算机表示方式就是补码的形式。在这个定义中,将字的最高有效位解释为负权。用函数B2TW表示,函数B2TW是一个双射。
- 原理:补码编码的定义
对向量 X = [Xw-1,Xw-2,…,X0]:
最高有效位Xw-1也称为符号位,"权重"为-2w-1,是无符号表示中权重的负数。符号位设置为1时,表示值为负,而当设置为0时,值为非负。 - 取值范围:
- 最小值的位向量为[10…0],其整数值为TMinw=-2W-1
- 最大值的位向量为[01…1],其整数值为TMaxw=2W-1-1
- 注意:
- 在取值范围内的每个数字都有一个唯一的w位的补码编码,即补码编码的唯一性。补码的范围时不对称的:|TMin|=|TMax|+1,即TMin没有与之对应的正数。之所以有这样的不对称性,是因为一半的位模式(符号位为1)表示负数,而另一半(符号位为0)表示非负数。因为0是非负数,因此表示整数的值比表示负数的值少一个。
- 最大的无符号数值刚好比补码的最大值的两倍大一点:UMaxW=2TMaxW+1
- 有符号数的其他两种表示方法:
反码:除了最高有效位的权是-(2w-1-1)而不是-2w-1,它和补码是一样的:
原码:最高有效位的符号位,用来确定剩下的位应该取负权还是正权:
- 有符号数和无符号数之间的转换
C语言允许在各种不同的数字数据类型之间转换。- 处理同样字长的有符号数和无符号数之间相互转换的规则是:数值可能改变,但是位模式不变。
- 函数U2BW和T2BW,它们将数值映射为无符号数和补码形式的位表示。即给定0≤X≤UMaxW范围的一个整数x,函数U2BW(X)会给出x的唯一的w位无符号表示。相应的,当x满足TMinW≤X≤TmaxW,函数T2BW(X)会给出x的唯一的w位补码表示
- T2UW(X)定义为T2UW(X)=B2UW(T2BW(X))
U2TW(X)定义为U2TW(X)=B2TW(U2BW(X)) - 补码和无符号数之间的转换
- 补码转无符号数
对于满足TMinW≤X≤TmaxW的x有:
- 无符号数转补码
对于满足0≤x≤UMaxW的x有:
- 补码转无符号数
- C语言中的有符号数和无符号数
- C语言支持所有整型数据类型的有符号和无符号运算。大多数机器使用的是补码,而且都默认为是有符号的,要创建一个无符号常量,必须加上后缀字符’U’或’u’。允许有符号和无符号之间的转换,而且,转换的原则是底层的位表示保持不变。从无符号数向有符号数转换的时候,用函数U2Tw,从有符号数转无符号数时,用函数T2Uw,其中w表示数据类型的位数
- 类型转换
- 显示强制类型转换
int tx,ty; unsigned ux,uy; tx = (int) ux; uy = (unsigned) ty;
- 隐式类型转换
int tx,ty; unsigned ux,uy; tx = ux; uy = ty;
- 显示强制类型转换
- 当用printf输出数值时,%d表示有符号十进制数,%u表示无符号十进制数,%x表示十六进制数
- 由于C语言对同时包含有符号和无符号数表达式的两种处理方式,因此,当执行一个运算的时候,如果它的一个运算数时有符号的而另一个时无符号的,那么C语言会隐式地将有符号参数强制类型转换为无符号数,并假设这两个数都是非负的,来执行这个运算
- 扩展一个数字的位表示
- 一个常见的运算是在不同字长整数之间转换,同时又保持数值不变
- 大的数据类型转小的数据类型是不可能的
- 小的数据类型转大的数据类型是可以的
- 无符号数的零扩展:要将一个无符号数转换为一个更大的数据类型,只需要在表示的开头添加0.这种运算称为零扩展w
原理:无符号数的零扩展
定义宽度为w的位向量 U = [UW-1,UW-2,…,U0]和宽度为w’的位向U’ = [0,…,0,UW-1,UW-2,…,U0],其中w’>w。则B2UW(U) = B2UW’(U’) - 补码数的符号扩展:要将一个补码数字转换为一个更大的数据类型,可以执行一个符号扩展,在表示中添加最高有效位的值
原理:补码数的符号扩展
定义宽度为w的位向量X = [XW-1,XW-2,…,X0]和宽度为W’的位向量 X’=[XW-1,…,XW-1,XW-1,XW-2,…,X0],其中,W’>W。则B2TW(X) = B2TW(X’) - 从一个数据大小到另一个数据大小的转换,以及无符号和有符号数字之间的转换的相对顺序能够影响一个程序的行为
- 一个常见的运算是在不同字长整数之间转换,同时又保持数值不变
- 截断数字
当将一个w位的数X = [XW-1,XW-2,…,X0]截断为一个k位数字时,我们会丢弃高w-k位,得到一个位向量X =[XK-1,XK-2,…,X0]。截断一个数字可能会改变它的值-----溢出的一种形式。- 原理:截断无符号数
令X等于位向量[XW-1,XW-2,…,X0],而X’是将其截断为k位的结果:X’ = [XK-1,XK-2,…,X0]。令X = B2UW(X),X’ = B2UK(X’)。则X’ = X mod 2k - 原理:截断补码数值
令X等于位向量[XW-1,XW-2,…,X0],而X’是将其截断为k位的结果:X’ = [XK-1,XK-2,…,X0]。令X = B2UW(X),X’ = B2TK(X’)。则X’ = U2TK(X mod 2k)
- 原理:截断无符号数
- 关于有符号数和无符号数的建议
有符号数和无符号数的隐式转换,会导致错误或者漏洞
当我们把字看做是位的集合而没有任何的数字意义时,无符号数值是非常有用的。例如,往一个字中放入描述各种布尔条件的标记时。地址也是无符号的。实现模运算和多精度运算的数学包时,数字是由字的数组来表示的,无符号值是非常有用的