教材学习内容总结
三种最重要的数字表示:
* 无符号
* 补码
* 浮点数
运算:
* 整数运算
* 浮点运算
对比:
整数运算只能编码相对较小的范围,但是是精确的;
浮点运算可以编码一个较大的范围,但是是近似的;浮点运算不可结合。
注意:溢出——运算位数的限制
计算机最小的可寻址的存储器单位——字节
一个字节的值域:00H-FFH
以0x或0X开头的数字常量为十六进制
常用进制:二进制(B),十进制(D),八进制(O或者Q),十六进制(H)
字长决定虚拟地址空间的最大大小。
字长为w,虚拟地址的范围为1-(2^w-1)
w=32或64:也就是我们通常所说的电脑是32位还是64位。也可以理解为CPU一次处理数据的位数。
在不同字长的计算机中,相同的数据类型所占用的字节数并不相同。
gcc -m32 可以在64位机上生成32位的代码
c语言中字符串被编码成为一个以null(值为0)字符结尾的字符数组。多使用ASCII字符码。
二进制代码在不同的操作系统上有不同的编码规则。所以二进制代码是不兼容的。
与: &
或: |
非: ~
异或:^
位向量的应用——表示有限集合。
※常见用法:掩码——用来选择性的屏蔽信号
掩码是一个位模式,表示从一个字中选出的位的集合。
用位向量给集合编码,通过指定掩码来有选择的屏蔽或者不屏蔽一些信号,比如
某一位位置上为1时,表明信号i是有效的;0表示该信号被屏蔽。
这个掩码就表示有效信号的集合。
举一个掩码的例子:
0xFF,表示屏蔽除最低有效字节之外的所有字节。
所以任取一个数x=0x934ADFEC,x&0xFF=0x000000EC
位级表达式的计算,要将通过转化为二进制表示进行二进制运算再转换回原来的进制来进行。
~0:生成一个全1的掩码。
与:&&
或:||
非:!
逻辑运算和位运算的区别
1.只有当参数被限制为0或1时,逻辑运算才与按位运算有相同的行为。
2.如果对第一个参数求值就能确定表达式的结果,逻辑运算符就不会对后面的参数求值。
x<>
右移分为逻辑右移和算术右移。(其实左移也区分,但是算术左移和逻辑左移没有什么区别)
逻辑右移:
在左端补k个0,多用于无符号数移位运算
算术右移:
在左端补k个最高有效位的值,多用于有符号数移位运算。
Java中用>>表示算术右移,用>>>表示逻辑右移。左移同样。
移位运算的优先级比算术运算(比如+、-)要低
整型数据类型——表示有限范围的整数,每种类型都能用关键字来指定大小,还可以指定是非负数(unsigned)还是负数(默认)。这些不同大小的分配的字数会根据机器的字长和编译器有所不同。
关于取值范围
要用C99中的“long long”类型,编译是要用 gcc -std=c99
无符号数的二进制表示的一个重要性质:
0-(2^w)-1中的每一个整数和长度为w的位向量是一一对应的。
关于补码的知识:
有符号数的其他表示方法:
从位级角度考虑。
强制类型转换的结果保持位值不变,只是改变了解释这些位的方式。即:这些位上的值不变,但是由于最高有效位的权重发生变化,从而导致结果发生改变。
负数——转换成大正数
以2的w-1次方为界限:
大于它——转换为负数值
扩展——从一个较小的数据类型转换为较大的数据类型,同时保持数值不变。
多用于无符号数转换为一个更大的数据类型。
只需在开头加上0即可。
多用于补码数字转换
最高有效位是什么,就添加什么。
注:无符号和有符号数字之间的转换,和数据的大小的转换,这之间的相对顺序能够影响到一个程序的行为。具体见联系2.23。
不用额外的位来扩展数值,而是减少表示一个数字的位数。而这么做可能会改变它的值,这也是溢出的一种形式。
将一个w位的数截断为k位数字时,就会丢弃高w-k位。
对于无符号数来说,就相当于 mod 2的k次幂
对于有符号数来说,先按照无符号数截断,然后再转化为有符号数
无符号数适用于没有任何数字意义的位的集合,比如地址;又或者实现模运算、多精度运算的时候,数字由字的数组表示的时候。
编程中多用有符号数。
——实际上这是一种模运算。
无符号运算本质上就是模运算,mod 2的w次幂。
涉及到的相关知识有:交换群(阿贝尔群),单位元,加法逆元等等。计算起来很简单。
两个w位的无符号数相乘,实际上是截取了低w位,但是等价于mod 2的w次幂。
总之就是模幂运算。
两个数的w位补码之和与无符号之和有完全相同的位级表示。
溢出
补码加法的溢出情况比无符号运算更为复杂,分为正溢出、正常、负溢出。正溢出就是超过正数的最大范围,负溢出就是超过负数的最大范围,具体的公式在书58页,正负溢出的范围和原因,直观一点的图在59页。
但是其实公式里给的本质仍然是模运算,模掉w位的补码最高有效位的权重2的w次幂。
对于范围在[-2^(w-1),2^(w-1))中的x,补码的非运算有如下两种情况:
x=-2^(w-1)时,为-2^(w-1)
x>-2^(w-1)时,为-x
c语言中的有符号乘法是通过将2w位的乘积截断为w位的方式实现的。也就是说,需要mod 2的w次幂。
所以:对于无符号和补码乘法来说,乘法运算的位级表示都是一样的。
在机器运算中,乘法总是很慢的,而加法和移位(左移)是相对较快的。所以在编译器中,会使用移位和加法运算组合的方式来代替乘以常数因子。这种方法对于无符号运算和补码运算都是适用的。
直接左移k位即可。
将常数C表示为2的几个整数次幂的和,结合移位运算和加法运算。
溢出?不影响结果。
机器运算中,除法比乘法更慢。当被除数为2的整数次幂时,通过右移来解决。右移时需要区分无符号数和补码。
需要注意:整数除法总是舍入到零
无符号数除以2的k次幂,就等同于对其逻辑右移k位。
补码进行算术左移时,需要考虑补码数的正负,因为整数除法总是舍入到零,无符号数中没有负数不必担心,但补码中有正有负,正数向下舍入到零,负数应该向上舍入到零。所以这里涉及到在移位前偏置。
也就是说:
与乘法不同,这种右移方法不能推广到任意常数C。
浮点表示对形如V=x X (2^y)的有理数进行编码,适用于:
非常大的数字
非常接近于0的数字
作为实数运算的近似值
小数的二进制表示法只能表示那些能够被写成x X (2^y)的数,其他的值只能近似的表示。
权重
以小数点为界:
左边第i位,权重为2的i次幂
右边第i位,权重为1/2的i次幂
用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)
即exp的位模式既不全0也不全1的时候,这是最一般最普遍的情况,因而是规格化的。
这里是以偏置形式表示的有符号整数。
阶码E = e-Bias
Bias=[2^(k-1)-1]
二进制小数点在小数字段最高有效位的左边。
尾数M = 1+f(隐含的以1开头的表示)
即阶码域全为0时的数。
阶码E = 1-Bias
尾数M = f(小数字段的值,不包含隐含的1)
a. 提供了一种表示数值0的方法。
b. 表示那些非常接近零的数。逐渐溢出
特殊值是在阶码位全为1的时候出现的。分为两种情况:
小数字段全为0
首先我们要知道,浮点运算只能近似的表示实数运算。
舍入运算:找到和数值x最接近的匹配值x‘,可以用期望的浮点形式表示出来。
IEEE浮点格式定义了四种不同的舍入方法:
即:将数字向上或向下舍入,是的结果的最低有效数字为偶数。
能用于二进制小数。
即:把整数向下舍入,负数向上舍入。
正数和负数都向下舍入。
正数和负数都向上舍入。
默认的(即向偶舍入)方法可以得到最接近的匹配,其余三种可用于计算上界和下界。
int、float、double相互转换?
int → float 不会溢出但有可能舍入
int/float → double 结果保留精确数值
double → float 可能溢出为±∞,由于精确度较小也有可能被舍入
float/double → int 向零舍入,可能溢出。
原文:http://www.cnblogs.com/nizaikanwoma/p/5928080.html