三种重要的数字表式:
1、 无符号数:编码基于传统的二进制表示法表示大于或等于零的数字。
2、 补码:编码是表示有符号整数的最常见方法,可以是正或者是负的数字。
3、 浮点数:编码是表示实数的科学计数法的以二位基数的版本
2.1 信息存储
c语言中,0x或者0X开头的数字常量被认为是十六进制的值。
常用进制:二进制(B),十进制(D),八进制(O或者Q),十六进制(H)
转换为二进制-十六进制相互转换,二进制的四位数字对应十六进制的一位数字。
每台计算机都有一个字长,指明整数和指针数据的标称大小,字长为w,虚拟地址的范围为1-(2^w-1)。
w=32或64:也就是我们通常所说的电脑是32位还是64位,也可以理解为CPU一次处理数据的位数。
小端法和大端法:
小端法:最低有效字节在前面——“高对高,低对低”
大端法:最高有效字节在前面
c语言中字符串被编码成为一个以null(值为0)字符结尾的字符数组。多使用ASCII字符码。
在使用ASCII字符码的任何系统上都能得到相同的结果,与字节顺序和字大小规则无关,所以文本数据比二进制数据具有更强的平台独立性。
二进制代码在不同的操作系统上有不同的编码规则,所以二进制代码是不兼容的,二进制代码很少能在不同机器和操作系统组合之间移植。
布尔代数:
常用运算符号:与 或 非 异或
扩展到位向量:位向量是有固定长度为w、由0和1组成的串,位向量的运算可以定义成参数的每个对应元素之间的运算。
位向量的一个很有用的应用就是表示有限集合。
c语言的一个很有用的特性就是支持按位布尔运算,确定一个位级表达式的结果最好的方法是将十六进制参数扩展成二进制并执行二进制运算,之后再转回十六进制。
位级运算的一个常见用法是掩码运算,掩码运算是一个位模式,表示从一个字中选出的位的集合。
c语言还提供了一组逻辑运算符:||,&&,!,分别对应or,and,not运算。
逻辑运算和位运算的区别
1.只有当参数被限制为0或1时,逻辑运算才与按位运算有相同的行为。
2.如果对第一个参数求值就能确定表达式的结果,逻辑运算符就不会对后面的参数求值
c语言还提供了一组移位运算。
2.2 整数表示
整型数据类型——表示有限范围的整数,每种类型都能用关键字来指定大小,还可以指定是非负数(unsigned)还是负数(默认)。这些不同大小的分配的字数会根据机器的字长和编译器有所不同。
32位机器和64位机器对于同一数据类型的典型取值范围是有所不同的。
典型取值范围中,负数的取值范围比整数的范围大1。
c语言标准定义的每种数据类型必须能够表示的最小的取值范围中,正数和负数的取值范围是对称的。
无符号数的编码:每个介于0~2^w -1之间的数都有唯一一个w位的值编码。
补码编码:
在补码编码的定义中,将字的最高有效位解释为负权,最高有效位也称为符号位,当设置为1时为负,设置为0时为正。
注意:补码的范围是不对称的,因为一半的数的整数一半是负数,而0是非负
数,最大的无符号数值刚好比补码的最大值的两倍大一点。
有符号数还有其他两种标准的表示方法:反码和原码
2.3 整数运算
1.无符号加法:
可以被视为模运算形式,等价于计算和模2^w,其实相当于丢弃溢出的最高位。
2.补码加法:
需要注意的是,必须确定结果太大或者太小时应该如何处理。
负溢出得到的结果比整数和大16,正溢出得到的结果比整数小16。
3.补码的非
4.无符号乘法:计算乘积模2^w
5.补码乘法:
c语言中的有符号乘法是通过将2w位的乘积截断为w位的方式实现的。表示整数
对于无符号和补码乘法来说,乘法运算的位级表示都是一样的。
6.乘以常数:
在机器运算中,乘法总是很慢的,而加法和移位(左移)是相对较快的。所以在编译器中,会使用移位和加法运算组合的方式来代替乘以常数因子。这种方法对于无符号运算和补码运算都是适用的。
常数为2的次幂时,直接左移即可,不是2的次幂时使用位移+加减法。
溢出不影响结果。
7.除以2的幂
对于无符号数,逻辑右移
对于补码,算数右移
8.总结
计算机执行的“整数”运算实际上是一种模运算模式,表示数字的有限字长限制了可能的值的取值范围,结果运算可能溢出,同时可以看到,补码提供了一种既能表示正数又能表示负数的灵活方法,同时使用了与执行无符号算数相同的位级实现。
2.4 浮点数
浮点表示对形如V=x X (2^y)的有理数进行编码,适用于:非常大的数字,
非常接近于0的数字,
作为实数运算的近似值
1.二进制小数
小数点以左是2的正次幂,以右是2的负次幂。
2.IEEE浮点表示
用V=(-1)^s X 2^E X M 来表示一个数:
符号:s决定这个数是正还是负。0的符号位特殊情况处理。
阶码:E对浮点数加权,权重是2的E次幂(可能为负数)
尾数:M是一个二进制小数,范围为1~2-ε或者0~1-ε(ε=1/2的n次幂)
将浮点数的位表示划分为三个字段,分别对这些值进行编码:
单独符号位s编码符号s,占1位
k位的阶码字段exp编码阶码E
n位小数字段frac编码尾数M(同时需要依赖阶码字段的值是否为0)
两种精度:
单精度(float),s=1位,k=8位,n=23位,一共32位;
双精度(double),s=1位,k=11位,n=52位,一共64位。
三种情况:
1.规格化的值:
exp的位模式既不全为0也不全为1,这种情况中,阶码字段被解释为以偏置形式表示的有符号整数。
阶码E = e-Bias(Bias=[2^(k-1)-1])
二进制小数点在小数字段最高有效位的左边。
尾数M = 1+f(隐含的以1开头的表示)
2.非规格化的值
当阶码域为全0时,阶码E = 1-Bias,尾数M = f(小数字段的值,不包含隐含的1)
非规格化提供了表示0和极接近0的数值的方法
3.特殊值
阶码全1时。
一种情况是无穷,一种情况是“不是一个数”
3.舍入
舍入运算的任务是找到和数值x最接近的匹配值x',可以用期望的浮点形式表示出来。
1.向偶数舍入
将数字向上或者向下舍入,使结果的最低有效数字是偶数。
2.向0舍入
3.向上舍入
4.向下舍入
34可以看上界下界。
向偶舍入可以得到最接近的匹配。
4.浮点运算
浮点加法:可交换,不可结合,满足单调性
浮点乘法:可交换,不可结合,不具分配性,满足以下单调性
5.c语言中的浮点数
当在int,float,double格式之间进行强制类型转换时,程序改变数值和位模式的原则如下:
从int转float:数字不会溢出但是可能被舍入
从int或float转double:因为double具有更大的范围,也有更高的精度,所以可以保留精确的数值
从double转float:因为范围要小一些,所以值可能溢出成为正负无穷大,另外由于精度小,还可能被舍入
从float或double转int:值会向0舍入