深入理解操作系统(4)第二章:信息的表示和处理(3)整数运算+浮点数(包括:溢出/模运算/时钟周期/字符编码/补码)
问题:
1. 两个正数相加可能会得出一个负数
int i = 2147483647;
printf("Hello world %x %d\n",i,i);
printf("Hello world %x %d\n",i+i,i+i);
结果:
Hello world 7fffffff 2147483647
Hello world fffffffe -2
3. 比较表达式 x<y 和比较表达式 x-y<0 会产生不同的结果
这些属性是计算机运算的有限性造成的。
理解计算机运算的细微之处能够帮助程序员编写更可靠的代码。
1. 整数运算
1.1 无符号加法
1.1.1 两个非负整数的和可能会溢出(算术运算溢出)
算术运算溢出:指完整的整数结果不能放到数据类型的字长限制中去。
两个正数相加可能会得出一个负数
解决:
尽量避免出现这种情况,如果数很大则使用 unsigned long 或者 unsigned long long 类型进行处理
1.1.2 无符号运算可以被看做一种形式的模运算。
无符号加法等价于计算模2的w次方的和。
1.1.3 例子:
可以通过简单丢弃x+y的w+1位表示的高位,来计算这个数值。
比如,考虑一个四位数字表示,x=9和y=12位表示分别为[1001]和[1100]它们的和是21,
五位的表示为[10101]。但是如果我们丢弃最高位也就是[0101] 5,这就和 21 mod 16 = 5一样。
2.9
这正好是C中执行两个w位无符号数值加法时我们得到的结果。
1.1.4 阿尔贝群
模数加法形成了一种数学结果,叫做阿尔贝群,丹麦数学家命名的。
注:这个后面第二遍的时候再深入学习它。
1.2 补码加法
两个数的w位二进制补码之和与无符号之和有完全相同的位级表示。
实际上,大多数计算机使用同样的机器指令来执行无符号或者有符号加法。
1.2.1 负溢出
两个负数相加得到一个非负数。
1.3 补码的非
一种有名的用来执行位级二进制补码的非( negation)的技术是,对每个位取反(或取补),然后将结果加1。
1.4 无符号乘法
2.3.4
1.5 补码乘法
我们认为对于无符号和二进制补码乘法来说,乘法运算的位级表示都是一样的。
1.6 乘以常数
1.7 乘以2的幂
在大多数机器上,整数乘法指令相当地慢,需要12或者更多的时钟周期,然而其他整数运算——例如加法、减法、位级运算和移位——只需要1个时钟周期。
因此,编译器使用的一项重要优化就是试着用移位和加法运算的组合来代替乘以常数因子的乘法
推理一坨公式略……
总结:
无论是无符号运算还是二进制补码运算,乘以2的幂都可能会导致溢出。
我们的结果表明,即使溢出的时候,我们通过移位得到的结果也是一样的。
时钟周期:时钟频率的倒数,一般是10ms。
参考:
linux 时间 time(2)-频率(时钟周期/指令周期/CPU周期)和 jiffies
https://blog.csdn.net/lqy971966/article/details/110234641
1.8 除以2的幂
在大多数机器上,整数除法要比整数乘法更慢——需要30或者更多的时钟周期。除以2的幂也可以用移位运算来实现,只不过我们用的是右移,而不是左移。对于无符号和二进制补码数,分别使用逻辑移位和算术移位来达到目的。
2. 浮点数
这部分略去,因为实际开发中几乎用不到浮点数的复杂运算。
后面第二遍的时候再深入学习。
二进制小数
IEEE浮点表示
数字示例
舍入
浮点运算
C语言中的浮点数
3. 第二章总结
1.计算机将信息编码为位(位),通常组织成字节序列;
源文件 hello.c 实际是由0和1组成的位序列,8个位组成一个字节。使用ASCII标准表示文本字符。
系统中所有的信息,包括磁盘文件,内存中程序,用户数据及网络数据都是一串的比特位表示。
2.不同的编码方式用来表示整数,实数和字符串
通俗易懂说–字符编码(ASCII,GB2312,GBK,Unicode,UTF-8/16/32,BOM
https://blog.csdn.net/lqy971966/article/details/89284662
3.不同的计算机模型在编码数字和多字节数据中的字节顺序上使用不同的约定。
通俗易懂说字节序,大小端,网络序和主机序
https://blog.csdn.net/lqy971966/article/details/93602177
4.大多数计算机对整数使用二进制补码编码,而对浮点数使用IEEE编码
有符号数和无符号数详解(2)补码详解
https://blog.csdn.net/lqy971966/article/details/106130830
5.c语言的标准规定在无符号和有符号整数之间进行强制类型转换时,基本位模式不应该改变。
6.由于编码的长度有限,计算机运算与传统整数和实数运算相比,具有非常不同的属性。
当超出范围时,有限长度能够引起数值溢出。
7.有符号数和二进制补码的运算都满足环的属性。这就允许编译器做很多的优化。
8.必须非常小心的使用浮点运算,因为浮点运算的范围和精度有限,而且浮点运算并不遵守普遍的算术属性,比如结合性。