读书笔记--编程珠玑II
学化学的应该都知道chemdraw,这是一款专门绘制化学结构的软件,什么苯环、双键各种word难以搞定的分子式,你可以轻松的用chemdraw完成,可以称得上化学工作者居家旅行必备的良药。其实早在1987年的时候,贝尔实验室的大牛Brian Kernighan(就是K&R教你写C语言中的K)和人一起设计了Chem语言,到现在还能用,似乎在书籍排版上比chemdraw的效果更好。说了这么多,咱不是给Chem做广告,而是为了引出它的另一位创作人Jon Bebtley,也是本文即将谈到的《编程珠玑II》——非常受程序员欢迎的系列书籍的作者。
《编程珠玑II》是一部短文集,涵盖了程序员操纵程序的技术、程序员取舍的技巧、输入和输出设计以及算法示例。
开头提到的Chem语言是Pic语言的预处理器,通过作者在书中第9章讨论的Pic语言一例,我们能够明白按照语言的特性对程序进行检查,可以帮我们更好地理解所使用的语言工具,并能教会我们为以后的程序设计更优雅的界面。
编程语言设计原则
- 设计目标:设计语言之前,要认真研究你试图解决的问题。
- 简单性:让你的语言尽可能地简单。规模小的语言便于实现者设计、创建、写文档和维护、也便于使用者学习和使用。
- 基本的抽象:常见的程序设计语言是基于冯・诺伊曼计算机的视角进行创建的,其指令只对小块的数据进行操作。基本对象就是程序的抽象数据类型,而操作就是关键的字程序。
- 语言的结构:表达式的自然性和实现的方便性需要做出权衡,缩进和注释都是必需的。
- 正交性:问题中不相关的特性在语言中也不相关;
- 设计语言的准绳:
- 一般性:一种操作用于多种目的;
- 简约性:去掉不需要的操作;
- 完全性:所设计的语言能描述所有感兴趣的对象吗?
- 相似性:让语言尽可能有启发性;
- 可扩展性:确定语言可以进一步发展;
- 开放性:允许用户“溜走”以使用其它工具;
- 设计过程:在实现语言之前,通过描述语言中大量的对象来测试你的设计,当语言完成并付诸实用后,还要反复进行新的设计已根据客户的需要加入新特性。
- 对编译器生成的深刻见解:尽可能地从后端的处理过程中将前端的语言分析分离出来,这样处理器的创建更容易,也更容易兼容到系统或新的语言用途中。
文档设计和编程有诸多相似之处,书中第10章通过几副不断完善的表格、插图,穿插着介绍了文档设计的原则。
文档设计
文档生成和编程有很多共同之处,两者都要“创造对他人有用的东西”和“必须出色的完成论文”,两者最大的共同点是都能让人尽享“创造的乐趣”。
文档设计需要创意。如果所有人着装相同,所有车的车型和颜色也一样,那么这个世界是多么地乏味。一个所有风格看上去差不多相同的文档库也是一样。综合考虑文档的许多属性,才能得到最佳的计效果。
但是要当心创意过度,好的排版并不能弥补文章本质上的缺陷,如拼写错误、语法不当、结构性差以及内容空洞等。好的文档风格就像好的编程风格和好的写作风格一样,是无形的。内容是文档的首要目的,文档风格只是达到这一目的的辅助手段。
合适的方式表达思想,参考勾股定理:”直角三角形的斜边地平方等于两直角边的平方和“,可以用下图和等式a²+b²=c²来表达这一信息
也可以用欧几里得表示法
根据计算机摩尔定律,我们可以存储越来越多的数据,并对其进行越来越多的处理,可是在系统执行了大量计算后,我们又该如何从海量数据中得出大趋势呢?
图形化输出
你如何概述拿破仑1812年在俄罗斯战役中的挫败?很多程序猿会试着打印出几十厘米数据(每天的人员数量、军饷、驻军地点),法国工程师Charles Joseph Minard在1861年用一种不同的方式来描述这个问题:只用一张简单的图来总结该战役。有人评价这可能是有史以来最好的统计学绘图。
本图给出了与地图上的城市、河流等背景相关联的六个变量:驻军地点(经纬度)、军队规模(和带宽成比例)、行军方向、气温以及日期,从中可以看到一支军队的毁灭与一个帝国走向灭亡的起点。
最后来几个书中提到的算法:
随机取样
许多随机取样要求随机样本中没有重复元素,以下伪代码为算法S,这个算法把结构保存在集合S中,如果S的实现正确,并且RandInt产生随机整数,那么这个算法生成随机样本,每个M元子集的概率都是。
View Codeinitialize set S to empty Size := 0 while Size < M do T := randInt(1,N) if T is not in s then insert T in S Size := Size + 1算法S有很多优点:正确、相当高效、非常简洁,似乎好的不能再改进了。不幸的是Bob Floyd发现,当M=N=100时明显存在一个缺陷。当Size=99时,集合S缺一个整数。算法闭着眼睛乱猜整数,直到偶然碰上正确的那个为止,这平均需要猜100个随机数。这个分析假设随机数发生器是真正随机的。对于某些非随机排列,这个算法甚至不会停止。Floyd开始寻找一个算法,对于S中每个随机数只恰好调用一次RandInt。
View Codeinitialize set S to empty for J := N - M + 1 to N do T := randInt(1,J) if T is not in S then insert T in S else insert J in s牛顿迭代法计算K维空间两点距离
View CodeT := abs(A[1] - B[1]) Max := T: Sum := T*T for J := 2 to K do T := 2 to K do if T > Max then Max : = T Sum := Sum + T*T if Sum = 0.0 then return 0.0 Eps = 1.0e-7 Z := Max loop NewZ := 0.5 * (Z + Sum/Z) if abs(NewZ - Z) <= Eps*NewZ then break Z := NewZ return NewZ