老师推荐的,本人觉得很值得一看
数学和计算机
谨以本文献给正在学习计算机而忽视数学学习的同学们
同学们,希望你们在读这篇文章的时候保持足够的耐心,因为这是很多人成功或者失败的经验。当然,是指在计算机的学习中可能会忽视的一些东西。我们以李开复先生的一篇文章开始我们的叙述。
算法的力量
- - 摘自李开复
李开复 简介:
1961年生于台湾。
曾就读于卡内基梅隆大学,获计算机学博士学位,后担任副教授;
在苹果公司工作了六年,主管该公司的多媒体部门;
曾担任SGI公司的多媒体软件子公司———Cosmo Software的总裁;
1998年7月加盟微软公司,并于11月出任微软中国研究院(现微软亚洲研究院)院长;
2000年升任公司副总裁,调回总部负责自然界面部。李开复是国际知名的语音识别技术专家,原为卡耐基梅隆大学副教授,曾获《商业周刊》1988年“年度最重要的科学创新”称号。
现任Google全球副总裁、中国区总裁。
算法是计算机科学领域最重要的基石之一,但却受到了国内一些程序员的冷落。许多学生看到一些公司在招聘时要求的编程语言五花八门,就产生了一种误解,认为学计算机就是学各种编程语言,或者认为,学习最新的语言、技术、标准就是最好的铺路方法。其实,大家被这些公司误导了。编程语言虽然该学,但是学习计算机算法和理论更重要,因为计算机语言和开发平台日新月异,但万变不离其宗的是那些算法和理论,例如数据结构、算法、编译原理、计算机体系结构、关系型数据库原理等等。在“开复学生网”上,有位同学生动地把这些基础课程比拟为“内功”,把新的语言、技术、标准比拟为“外功”。整天赶时髦的人最后只懂得招式,没有功力,是不可能成为高手的。
当我在1980年转入计算机科学系时,还没有多少人的专业方向是计算机科学。有许多其他系的人嘲笑我们说:“知道为什么只有你们系要加一个‘科学’,而没有‘物理科学系’或‘化学科学系’吗?因为人家是真的科学,不需要画蛇添足,而你们自己心虚,生怕不‘科学’,才这样欲盖弥彰。” 其实,这点他们彻底弄错了。真正学懂计算机的人(不只是“编程匠”)都对数学有相当的造诣,既能用科学家的严谨思维来求证,也能用工程师的务实手段来解决问题——而这种思维和手段的最佳演绎就是“算法”。
记得我读博时写的Othello对弈软件获得了世界冠军。当时,得第二名的人认为我是靠侥幸才打赢他,不服气地问我的程序平均每秒能搜索多少步棋,当他发现我的软件在搜索效率上比他快60多倍时,才彻底服输。为什么在同样的机器上,我可以多做60倍的工作呢?这是因为我用了一个最新的算法,能够把一个指数函数转换成四个近似的表,只要用常数时间就可得到近似的答案。在这个例子中,是否用对算法才是能否赢得世界冠军的关键。
有人也许会说:“今天计算机这么快,算法还重要吗?”其实永远不会有太快的计算机,因为我们总会想出新的应用。虽然在摩尔定律的作用下,计算机的计算能力每年都在飞快增长,价格也在不断下降。可我们不要忘记,需要处理的信息量更是呈指数级的增长。现在每人每天都会创造出大量数据(照片,视频,语音,文本等等)。日益先进的记录和存储手段使我们每个人的信息量都在爆炸式的增长。互联网的信息流量和日志容量也在飞快增长。在科学研究方面,随着研究手段的进步,数据量更是达到了前所未有的程度。无论是三维图形、海量数据处理、机器学习、语音识别,都需要极大的计算量。在网络时代,越来越多的挑战需要靠卓越的算法来解决。
并行算法:Google的核心优势。每天Google的网站要处理十亿个以上的搜索,GMail要储存几千万用户的2G邮箱,Google Earth要让数十万用户同时在整个地球上遨游,并将合适的图片经过互联网提交给每个用户。如果没有好的算法,这些应用都无法成为现实。在这些的应用中,哪怕是最基本的问题都会给传统的计算带来很大的挑战。例如,每天都有十亿以上的用户访问Google的网站,使用Google的服务,也产生很多很多的日志(Log)。因为Log每分每秒都在飞速增加,我们必须有聪明的办法来进行处理。我曾经在面试中问过关于如何对log进行一些分析处理的问题,有很多面试者的回答虽然在逻辑上正确,但在实际应用中是几乎不可行的。按照他们的算法,即便用上几万台机器,我们的处理速度都跟不上数据产生的速度。那么Google是如何解决这些问题的呢?
首先,在网络时代,就算有最好的算法,也要能在并行计算的环境下执行。在Google的数据中心,我们使用的是超大的并行计算机。但传统的并行算法运行时,效率会在增加机器数量后迅速降低,也就是说,十台机器如果有五倍的效果,增加到一千台时也许就只有几十倍的效果。这种事倍功半的代价是没有哪家公司可以负担得起的。而且,在许多并行算法中,只要一个结点犯错误,所有计算都会前功尽弃。
那么Google是如何开发出既有效率又能容错的并行计算的呢?Google最资深的计算机科学家Jeff Dean认识到, Google 所需的绝大部分数据处理都可以归结为一个简单的并行算法:Map and Reduce。这个算法能够在很多种计算中达到相当高的效率,而且是可扩展的(也就是说,一千台机器就算不能达到一千倍的效果,至少也可以达到几百倍的效果)。Map and Reduce的另外一大特色是它可以利用大批廉价的机器组成功能强大的server farm。最后,它的容错性能异常出色,就算一个server farm里面的机器down掉一半,整个farm依然能够运行。正是因为这个天才的认识,才有了Map and Reduce算法。借助该算法,Google几乎能无限地增加计算量,与日新月异的互联网应用一同成长。
给程序员的七个建议
(1)练内功。不要只花功夫学习各种流行的编程语言和工具,以及某些公司招聘广告上要求的科目。要把数据结构、算法、数据库、操作系统原理、计算机体系结构、计算机网络,离散数学等基础课程学好。大家不妨试试高德纳所著The Art of Computer Programming里的题目,如果你能够解决其中的大部分题目,就说明你在算法方面有一定的功力了。
(2)多实战。通过编程的实战积累经验、巩固知识。很多中国大学毕业生缺乏编程和调试经验;学习C语言,考试过关就算学会了;课题项目中,只要程序能够编译,运行,并且输入输出满足要求就算了事。这些做法是不行的。写程序的时候,大家必须多想想如何把程序写得更加精炼、高效、高质量。建议大家争取在大学四年中积累编写十万行代码的经验。我们必须明白的是:好程序员是写出来的,不是学出来的。
(3)求实干。不要轻视任何实际工作,比如一些看似简单的编码或测试。要不懈追求对细节一丝不苟的实干作风与敬业精神。我发现不少程序员对于知识的掌握很肤浅,不求甚解,没有好奇心,不会刨根问底。比如,学会了C++,是否了解一个对象在编译后,在汇编代码中是如何被初始化的?这个对象的各个成员在内存中是如何存放的?当一个成员函数被调用时,编译器在汇编代码中加入了哪些额外的动作?虚函数的调用是如何实现的? 这些东西恐怕在编程语言或编译原理中都没有详细提到,只有通过踏实的实干才能真正掌握。
(4)重视数学学习。数学是思维的体操,数学无处不在。学计算机至少要学习离散数学、概率论、布尔代数、集合论和数理逻辑。这些知识并不难,但是对你未来的工作帮助会很大。 尤其当你对一些“数学密集型”的领域如视频、图像处理等有兴趣时,这些知识将成为你手中的利器。
(5)培养团队精神,学会与人合作。今天的软件工程早已经不是一个人可以单独操作的,而必须靠团队合作才能成功。不懂得合作的人是不能成大器的。大家要多去寻找可以与人一起做项目的机会。
(6)激励创新意识,培养好奇心,不要死记硬背。没有掌握某种算法技术的根本原理,就不会有应变和创新的能力。想成为一位好程序员(其实从事任何一个行业都是如此),重要的是要养成钻研,好奇,创新,动手,合作的优秀习惯,不满足于填鸭,不满足于考试交差,不满足于表象。这不是学几门课能够一蹴而就的。
(7)有策略地“打工”。在不影响学业的前提下,寻找真正有意义的暑期工作或兼职。去找一个重视技术的公司,在一个好的“老板”指导下完成真正会被用户使用的程序。不要急于去一个要你做“头”而独挡一面的地方,因为向别人学习才是你的目的。找工作也是一样,不要只看待遇和职衔,要挑一个你能够学习的环境,一个愿意培养员工的企业,一个重视你的专业的公司。最后,还要挑一个好老板。
希望大家都能把握机会,养成好的学习习惯,把算法学精学透;希望大家都能有一个美好的未来!
计算机与数学
在李开复先生的文章中的最后他对程序员提出了七点建议,其中有一条就是重视数学学习。计算机和数学有什么关系呢?
计算机自从其诞生之日起,它的主要任务就是进行各种各样的科学计算。文档处理,数据处理,图像处理,硬件设计,软件设计等等,都可以抽象为两大类:数值计算与非数值计算。作为研究计算机科学技术的人员,我们大都对计算数学对整个计算机科学的重要性有一些了解。但是数学对专业的研究和应用人员究竟有多大的用处呢?我们先来看一下下面的一个流程图:
上图揭示了利用计算机解决科学计算的步骤,实际问题转换为程序,要经过一个对问题抽象的过程,建立起完善的数学模型,只有这样,我们才能建立一个设计良好的程序。
四川大学数学学院的曹广福教授曾说过:“一个大学生将来的作为与他的数学修养有很大的关系”。大学计算机专业学生都有感触,计算机专业课程中最难的几门课程莫过于离散数学、编译原理、数据结构,当然像组合数学、密码学、计算机图形学等课程也令许多人学起来相当吃力,很多自认为数据库学得很好的学生在范式、函数依赖、传递依赖等数学性比较强的概念面前感到力不从心,这些都是因为数学基础或者说数学知识的缺乏所造成的。数学是计算机的基础,这也是为什么考计算机专业研究生数学都采用最难试题(数学一)的原因,当然这也能促使一些新的交叉学科如数学与应用软件、信息与计算科学专业等飞速发展。许多天才程序员本身就是数学尖子,众所周知,Bill Gates的数学成绩一直都很棒,他甚至曾经期望当一名数学教授,他的母校——湖滨中学的数学系主任弗雷福·赖特曾这样谈起过他的学生:“他能用一种最简单的方法来解决某个代数或计算机问题,他可以用数学的方法来找到一条处理问题的捷径,我教了这么多年的书,没见过像他这样天分的数学奇才。他甚至可以和我工作过多年的那些优秀数学家媲美。当然,比尔也各方面表现得都很优秀,不仅仅是数学,他的知识面非常广泛,数学仅是他众多特长之一。”。影响一代中国程序人的金山软件股份有限公司董事长求伯君当年高考数学成绩满分进一步说明了问题。很多数学基础很好的人,一旦熟悉了某种计算机语言,他可以很快地理解一些算法的精髓,使之能够运用自如,并可能写出时间与空间复杂度都有明显改善的算法。
程序设计当中解决的相当一部分问题都会涉及各种各样的科学计算,这需要程序员具有什么样的基础呢?实际问题转换为程序,要经过一个对问题抽象的过程,建立起完善的数学模型,只有这样,我们才能建立一个设计良好的程序。从中我们不难看出数学在程序设计领域的重要性。算法与计算理论是计算机程序设计领域的灵魂所在,是发挥程序设计者严谨,敏锐思维的有效工具,任何的程序设计语言都试图将之发挥得淋漓尽致。程序员需要一定的数学修养,不但是编程本身的需要,同时也是培养逻辑思维以及严谨的编程作风的需要。数学可以锻炼我们的思维能力,可以帮助我们解决现实中的问题。可以帮助我们更高的学习哲学。为什么经常有人对一些科学计算程序一筹莫展,他可以读懂每一行代码,但是却无法预测程序的预测结果,甚至对程序的结构与功能也一知半解,给他一个稍微复杂点的数学公式,他可能就不知道怎么把它变成计算机程序。很多程序员还停留在做做简单的MIS,设计一下MDI,写写简单的Class或用SQL语句实现查询等基础的编程工作上,对于一些需要用到数学知识的编程工作就避而远之,当然实现一个累加程序或者一个税率的换算程序还是很容易的,因为它们并不需要什么高深的数学知识。
一名有过10多年开发经验的老程序员曾说过:“所有程序的本质就是逻辑。技术你已经较好地掌握了,但只有完成逻辑能力的提高,你才能成为一名职业程序员。打一个比方吧,你会十八般武艺,刀枪棍棒都很精通,但就是力气不够,所以永远都上不了战场,这个力气对程序员而言就是逻辑能力(其本质是一个人的数学修养,注意,不是数学知识)。”
程序员的数学修养不是一朝一夕就可以培养的。数学修养与数学知识不一样,修养需要一个长期的过程,而知识的学习可能只是一段短暂的时间。下面是一些在业界普遍被承认的对于程序员如何提高与培养自己的数学修养的基本看法。
首先,应该意识到数学修养的重要性。作为一个优秀的程序员,一定的数学修养是十分重要也是必要的。数学是自然科学的基础,计算机科学实际上是数学的一个分支。计算机理论其实是很多数学知识的融合,软件工程需要图论,密码学需要数论,软件测试需要组合数学,计算机程序的编制更需要很多的数学知识,如集合论、排队论、离散数学、统计学,当然还有微积分。计算机科学一个最大的特征是信息与知识更新速度很快,随着数学知识与计算机理论的进一步结合,数据挖掘、模式识别、神经网络等分支科学得到了迅速发展,控制论、模糊数学、耗散理论、分形科学都促进了计算机软件理论、信息管理技术的发展。严格的说,一个数学基础不扎实的程序不能算一个合格的程序员,很多介绍计算机算法的书籍本身也就是数学知识的应用与计算机实现手册。
其次,自身数学知识的积累,培养自己的空间思维能力和逻辑判断能力。数学是一门分支众多的学科,我们无法在短暂的一生中学会所有的数学知识,像泛函理论、混沌理论以及一些非线性数学问题不是三五几天就可以掌握的。数学修养的培养并不在与数学知识的多少,但要求程序员有良好的数学学习能力,能够很快地把一些数学知识和自己正在解决的问题联系起来,很多理学大师虽然不是数学出身,但是他们对数学有很强的理解能力和敏锐的观察力,于是一系列新的学科诞生了,如计算化学、计算生物学、生物信息学、化学信息学、计算物理学,计算材料学等等。数学是自然学科的基础,计算机技术作为理论与实践的结合,更需要把数学的一些精髓融入其中。从计算机的诞生来看它就是在数学的基础上产生的,最简单的0、1进制就是一个古老的数学问题。程序设计作为一项创造性很强的职业,它需要程序员有一定的数学修养,也具有一定的数学知识的积累,可以更好地把一些数学原理与思想应用于实际的编程工作中去。学无止境,不断的学习是提高修养的必经之路。
第三,多在实践中运用数学。有些高等学校开设了一门这样的课程——《数学建模》。我在大学时期也曾学过,这是一门内容很丰富的课程。它把很多相关的学科与数学都联系在一起,通过很多数学模型来解决实际的生产生活问题,很多问题的解决需要计算机程序来实现。我在大学和研究生阶段都参加过数学建模竞赛,获得了不少的经验,同时也进一步提高了自己的数学修养。实际上,现在的程序设计从某些角度来看就是一个数学建模的过程,模型的好坏关系到系统的成败,现在数学建模的思想已经用于计算机的许多相关学科中,不单只是计算机程序设计与算法分析。应该知道,数学是一门需要在实践中展示其魅力的科学,而计算机程序也是为帮助解决实际问题而编制的,因此,应该尽量使它们结合起来,在这个方面,计算机密码学是我认为运用数学知识最深最广泛的,每一个好的加密算法后面都有一个数学理论的支持,如椭圆曲线、背包问题、素数理论等。作为一名优秀的程序员,应该在实际工作中根据需要灵活运用数学知识,培养一定的数学建模能力,善于归纳总结,慢慢使自己的数学知识更加全面,数学修养得到进一步提高。