读《编程卓越之道:深入理解计算机》

来源:互联网 发布:linux wifi 破解 编辑:程序博客网 时间:2024/05/05 03:41
       图书馆,淘金和充电的好地方。从刚上大一时,我就领略过其魅力了,当时很惊叹于借书处和阅览室的藏书,尤其是计算机阅览室里,各个方向的书籍应有尽有,那些名家巨著更是可谓汗牛充栋,还有那安静的环境,绝对是读书的胜地。要是能天天都来图书馆走上一遭,和那些软件巨匠们一起探索这个世界,那将是多么惬意的一件事情啊!只可惜,大一时“误入歧途”,没有觉察出学习的重要,终日无所事事,导致光阴几乎虚度。到了大二,开始慢慢觉醒,但是由于这时学院已经开设了很多相关课程,虽然没有时间光顾图书馆,但是在课业上也算是学有所成,打下了不错的专业基础,而且最后综合排名达到了2/305,聊以欣慰。现在保研了,终于有了充足的时间来做自己想做的事,因此泡馆,就理所当然地进了我的日程安排。
       前天开始阅读《编程卓越之道》系列丛书,全部共有4部,分别为《深入理解计算机》(<Understanding the Machine>),《运用底层语言思想编写高级语言代码》(<Thinking Low-Level, Writing High-Level>),《Engineering Software》,《Testing, Debugging, and Quality Assurance》。不过只可惜目前似乎只出了第一部。所谓深入理解计算机,就是从真正的底层开始了解计算机,包括各种数据的实际存储和表示,内存组织和管理等;而所谓卓越,就是编写高效代码。何谓高效?说简单点就是充分利用CPU和内存资源,说具体点就是我们写的代码转换为CPU运行指令的时候要尽可能地遵循CPU的运行规范,要尽可能地满足内存的分配原则。我这两天看了书的前四章,主要是关于数的表示存储。看了之后我才发现,原来真的有不少底层的东西是一般的书上所没有介绍的,我觉得有必要补充一下,因此从书中摘录出写在此文中(基本是书中原文,也有我的提炼)。其中有些是写高效代码的建议,有些则是我的学习新得。如果你也觉得有用,那我将很高兴。
1.在计算机中,数值和字符串之间的转换是很昂贵的。比如我们在C语言中用的最多的I/O函数:scanf和printf。其实我们在用键盘输入时,在缓存中存放的是字符串形式,而当"12345"被识别为计算机中的整数12345时,计算机采用的基本就是我们平时自己写练习函数时的算法,相信大家都写过。同样,printf在输出一个整数时,也需要将12345转换为"12345"后才输出到显示屏或其他终端上。呵呵循环的模运算的开销还是比较大的。
2.符号扩展,零扩展,符号缩减。在学习汇编的过程中,符号扩展和零扩展都是必讨论的话题。而符号缩减因为一般不常用所以没有详细讨论。符号缩减有可能会导致数值产生了变化,所以其安全解决是将缩减后的值与一对临界值(即原始值的误差容限)比较之后再决定是否缩减正确。然而如果频繁使用符号缩减的话,将会使代码充斥着if statements,可读性不言而喻。
3.饱和操作。对于音视频操作是合理的,因此Inter 80*86 CPU中的多媒体扩展指令MMX就支持饱和操作,别的CPU不支持的话也可以用代码实现。
4.有理数表示法。可以用n/d来表示一个小数,而其四则运算可以用简单的函数来实现。
5.模运算开销昂贵。尽量使用位与运算&代替,有时还可以用if statement实现一个有序数列的循环。
6.打包数据格式。可以将n个独立的存储变量“组合”成一个整体来缩减存储空间,并以此达到简化其操作对应的某些CPU指令,比如比较指令。典型的应用是声明了位域成员的结构体。但由于编译器的实现有别,影响了这种格式的可移植性。
7.有限精度算术。对于浮点数的表示,计算机只能做到有限精度。因此浮点数的运算会产生误差,甚至是放大误差。以下是一些建议。计算的顺序可以影响结果的准确性,在对符号相同的两个数做减法时,结果的精度可能比所用的浮点格式所能支持的精度要小,这意味着某些FPU或浮点软件包可能会在低端位上插入一些随机的数字来代替原来的0。在进行四则混合运算时,要尽可能先算乘除或算加减(但这样可能会增加乘除的次数,需权衡)。在对一组数做乘除时,尽量对数量级一样的先运算。在比较两个浮点数是否相等(或是大于,小于)时,要看一个是否在另一个的误差容限里,而不能直接比较。
8.扩展精度格式。包含额外的16个位,其中12个用于尾数,4个用于阶码。这些位在计算时起一定的精度保护作用,但结果写回时作下舍入。在Intel 80*86中,FPU全部采用扩展精度格式做浮点运算。
9.两种无法规格化的数。一是0。+0和-0取决于符号位。Intel推荐使用符号位来表示该0值是负数下溢产生的(符号位置1)还是正数下溢产生的(符号位置0)。二是高端是0,移位阶码也是0的极小数。IEEE允许使用反向规格化数来表示它们(或下溢到0)。不过尽管使用反向规格化数允许IEEE浮点运算产生比出现下溢更好的结果,但其有效位是很少的。
10.一般阶码是不会为全0或全1的,但也存在特殊情况。如果阶码全1而尾数非0(不含隐藏位),那么尾数最高位(仍不含隐藏位)为1表示该数是一个未明无效数字(QNaN, Quiet Not a Number),尾数最高位为0表示该数是一个明确无效数字(Signaling NaN)。QNaN表示不确定的结果,SNaN表示发生了无效操作。如果阶码全1而尾数全0,则符号位表示其是正无穷(+Infinity)还是负无穷(-Infinity)。还有就是阶码全0,则符号位表示该数是+0还是-0。
(To be continued...)
原创粉丝点击