[转载] 程序员怎样学数学:半路出家也能让编程是小菜一碟
自从我读了Johnny von Neumann的传记,我已经为弥补我糟糕的数学技能花了15个月了。
读了大量的数学书籍,不过呢,似乎我还有更多没有读。当然我会接着做的。
现在我就来告诉你这些。
告别传统观念
概要:编程和数学这两种可以相互促进的能力。
我常常听到这样的话:程序员不认为他们需要了解数学。
我不知道还有没有不同意的。甚至于以前是主修数学的程序员也告诉我他们真的不是常常使用到数学!他们说,更重要的是要去了解设计模式,面向对象原理,软件工具,界面设计,以及一些其他类似的东西。
你了解吗?他们完全正确。你不需要了解很多数学你就能做个很棒,很专业的程序员。
但是呢,同时你也不是真的需要知道如何来编程。我们要面对的是:有很多专业的程序员,他们认识到他们不是非常擅长数学,但他们还是寻找方法去提升。
如果你突然觉得自己好烂,周围的人都远远的超过你,你会怎么想呢?好,你可能会发现:自己善于项目管理,或人事管理,或界面设计,或技术写作,或系统管理,还有许多其他程序员不必去精通的。你会开始堆积那些想法(因为工作永远干不完),当你发现一些你能掌握的东西时,你很可能会转移去全职的做这个工作。
实际上,我认为有些东西你不需要了解,当前你还能够赖以生存的话。
所以他们是对的:你不需要了解数学,并且没有数学你也能过的很好。
但是最近我学到一些东西可能会让你也感到惊喜:在你知道如何编程之后,数学更容易学会。实际上,如果你先学数学,然后半路出家做程序员的话,你会发现编程简直就是小菜一碟。
学校里教数学的方式都错了。仅仅是教学的方法错了,不是教数学本身错。如果你以正确的方式学习数学的话,你会学的更快,记住这点,对你,作为一个程序员来说很有价值。
哪怕了解一点点相关的数学知识,就能让你写出可爱有趣的程序,否则会有些小难度。换句话讲,数学是可以慢慢学的,只要你有时间。
没人能了解所有的数学,就是最棒的数学家也不是。当人们发明新的形式去解决自己的问题时,数学领域就不断的扩展。一些给出的数学问题,也正如编程,不止一种方法可以去解决他。你可以挑个你最喜欢的方式。
数学是......嗯,请别告诉别人我说过这个哈;当然我也不指望谁能邀请我参加这样的派对,在我还活着的时候。但是,数学其实就是......我还是小声的说吧,听好了:(她其实就是一种乐趣啦!)
你学过并忘记的数学
概要:在学校中所学的很多数学知识,在编程中用不到。
这儿是我能记得的在学校学到的数学:
初中:数,数数,算术知识,初级代数(“带问题的小故事”)
高中:代数,几何,高等代数,三角学,微积分先修课 (二次曲线论和极限)
大学:微积分,微分公式,线性代数,概率和统计,离散数学
上面那个关于高中数学课程单子上所列的,怎么来着?美国高中几乎都是这样的课程设置。我认为其他国家也会很相似的,除了那些在9岁之前就掌握了这些课程的学生。(美国小孩同时却在热衷于玩魔鬼卡车竞赛,虽然如此,整个来说也算不上什么大损失。)
代数?是的。没问题。你需要代数,和一些理解解析几何的知识。那些很有用,并且在以后几个月里,你能学到一切你想要的,十拿九稳的。剩下的呢?我认为一个基本的介绍可能会有用,但是在这上面花整个学期或一年就显得很荒谬了。
我现在意识到那个书单列表原是设计来准备给那些以后要当科学家和工程师的学生的。他们在高中里所教的数学课程并不是为你的编程生涯做准备的,简单的事实是,多数的编程工作所需要的数学知识相比其他作为工程师角色的人所需要的数学增长的更快。
即使你打算当一名科学家或者一名工程师,在你理解了什么是数学之后-- 数学它如何而来,如何而去,为何而生,我发现这更加容易去学习和欣赏几何学和三角学。不必去专研记住几何上的证明和三角恒等式,虽然那确实是高中学校要求你必须去做的。
所以这样的书单列表不再有什么用了。学校教给我们的不是最合适的数学,并且方式也不对。不奇怪程序员认为他们不再需要数学:我们学的大部分数学知识对我们的工作没什么大的帮助。
学校没有教你的数学
概要:程序员们最需要的是离散数学、概率论和线性代数,而不是微积分。
在现实中,计算机科学家经常使用的数学,跟上面所列的数学仅有很小的重叠。举个例子,你在中学里学的大部分数学是连续性的:也就是说,那是作为实数的数学。而对于计算机科学家来说,他们所感兴趣的95%也许更多的是离散性的:比如,关于整数的数学。
我打算在以后的博客中再谈一些有关计算机科学,软件工程,编程,搞些有趣的东东,和其他常常令人犯晕的训练。我已经从Richard Gabriel的《软件的模式》这本书中洞察到一个无关巨细的基本框架。如果你明显的等不下去的话,去读吧。是本不错的书。
到现在为止,不要让“计算机科学家”这个词困扰到你。它听上去很可怕,其实数学不是计算机科学家所独有的领域,你也能作为一个黑客自学它,并且能做的和他们一样棒。你作为一个程序员的背景将会帮助你保持只关注那些有实践性的部分。
我们用来建立计算模型的,大体上是离散数学。这是普遍的做法。如果正好今天你在看这篇博客,从现在起你正了解到更多的数学,并且你会认识到那样的普遍做法是不对的。从现在开始,你将有信心认为可以忽略这些,并以你想要的方式自学。
对程序员来说,最有效的离散数学的分支是概率理论。这是你在学校学完基本算术后的紧接着的课。你会问,什么是概率理论呢?你就数啊,看有多少次出现满堂彩?或者有多次是同花顺。不管你思考什么问题如果是以“多少种途径...”或“有多大几率的...”,那就是离散问题。当他发生时,都转化成“简单”的计数。抛个硬币看看...?毫无疑问在他们教你基本的计算用法后他们会教你概率理论。
我还保存着大学里的离散数学课本。可能他只占了三分之一的课程,但是它却涵盖了我们几乎每天计算机编程工作大部分所用到的数学。
也真是够奇怪的,我的教授从没告诉我数学是用来干吗的,或者我也从来没有听说过。种种原因吧。所以我也从没有给以足够的注意:只是考试及格然后把他们都忘光,因为我不认为她还和编程有啥关系,事情变化是我在大学学完一些计算机科学的课程之后,也许是25%的课程,可怜啊!我必须弄明白什么对于自己来说是最重要的,然后再是向深度发展。
我想,如果每门数学课都花上整整一周的时间,而只是介绍让你如何入门的话,那将非常不错,这是最有意思的一种假设,那么你知道了你正学习的对象是哪种怪物了。怪物,大概对每一门课都合适。
除了概率和离散数学外,还有不少其他的数学分支,可能对程序员相当的有用,学校通常不会教你的,除非你的辅修科目是数学,这些数目列表包括:
统计学,其中一些包括在我的离散数学课里,她的某些训练只限于她自身。自然也是相当重要的,但想学的话不需要什么特别的入门。
代数和线性代数(比如:矩阵)。他们会在教完代数后立即教线性代数。这也简单,这但相当多的领域非常有用,包括机器学习。
数理逻辑。我有相当完整的关于这门学科的书没有读,是 Stephen Kleene写的,克林闭包的发明者,我所知道的还有就是Kleenex。这个就不要读了。我发誓我已经尝试了不下20次,却从没有读完第二章。如果哪位牛掰有什么更好的入门建议的话可以给我推荐。虽然,这明显是非常重要的一部分。
信息理论和柯尔莫戈洛夫复杂性理论。真不可思议,不是么?我敢打赌没哪个高中会教你其中任何一门课程。她们都是新兴的学科。信息理论是(相当相当相当相当难懂)关于数据压缩,柯尔莫戈洛夫复杂性理论是(同样非常难懂)关于算法复杂度的。也就是说,你要把它压缩的尽量小,你所要花费的时间也就变的越长,同样的,程序或数据结构要变得多优雅也有同样的代价。
他们都很有趣,也很有用。
当然,也有其他的一些因素,某些领域是重复的。也拿来说说吧:你所发现有用的那部分数学,不同于那些你在学校里认为有用的数学。
那微积分呢?每个人都学它,所以它也一定是重要的,不对吗?
好吧,微积分实际上是相当容易的。在我学习它之前,它听上去好像是世界上最难的一件事,好像和量子力学差不多。量子力学对我来说真的不是那么容易理解,但是微积分却不是。在我意识到程序员能够快速的学习数学时,我拿起一些微积分课本用一个月通读了整本书,一个晚上读一小时。
微积分都是关于连续统的 -- 变化的比率,曲线的面积,立体的体积。是些有用的东西,但是实际细节却包含大量的记忆量并且枯燥,作为一个程序员来说根本不需要这些。更好的方法是从整体上了解那些概念和技术,在必要的时候再去查询那些细节。
几何,三角,微分,积分,圆锥曲线,微分方程,和他们的多维和多元 -- 这些都有重要的应用。不过这时候不需要你去了解它们。这大概不是个好注意让你年复一年的去做证明和它们的练习题,不是吗?如果你打算花大量的时间去学习数学,那也是和你生活相关的部分。
学习数学的正确方法
概要:1.广度优先,而不是深度优先。2.明确理论要解决的问题。不纠结于符号,而是要深入的探求数学的本质。3.使用编程语言来进行数学计算。
正确学习数学的方法是广度优先,而非深度优先。你要考察的是整个数学世界,学习每个概念的名字,区分出什么是什么。
具体的来看,考虑用长除法?如果你能在纸上做长整除,现在就举起你的手,会有人举手吗?至少我不这么认为。
回头看看在学校里学过的长除法,要是不让你觉得烦恼和愤怒才怪。当然,这是显然的,但你不一定要自己亲自去做,因为很容易用计算器来做,即使你不幸在一座没有电力的荒无人烟的小岛上。你起码还有个计算器,在的手表上,补牙的什么东东,或其他什么上面。
为什么他们还教你这些呢?为什么我们感到含混心虚讷,如果我们不能记住怎样去做?这不是好像我们需要再次知道她。除此以外,如果你命悬一线,你可以运用任意大的数来做长除法。相象你被囚禁在第三世界的地牢里,那儿的独裁者是不会放你出来的,除非你计算出 219308862/103503391。你会怎么做呢?好吧,很容易。你开始从分子减去分母,直到不能再减只剩余数为止。若实在有压力,你可以想个办法,继续使用反复减,估算作为十进制的余数(这种情况下,0.1185678219,Emacs M-x calc 告诉我的。够精确了!)
你或许明白,除法就是反复的减。这样从直觉上对除法概念的理解就根深蒂固啦!
学习数学的正确方法是忽略实际的算法和证明,对于大部分情况来说,他们的名字,他们的作用,他们计算的大致步骤, (有时是)谁发明了他们,发明了多久了,他们的缺陷是什么,和他们相关的有什么。把数学当文科来学。
为什么呢?因为第一步反应在数学上的是问题的确定。如果你有一个问题去解决,并且假设你没有头绪如何开始,这将花费你很长的时间来弄明白。但如果你知道这是个变异的问题,或者是一个凸优化问题,或者一个布尔的逻辑问题,然后你起码能知道从哪着手开始寻找解决方案。
现在有许许多多的数学技术和整个的学科分支。如果你不知道组合逻辑是什么,甚至连听都没听说过,那么你是不可能意识到在组合逻辑中可以找到的解决答案的问题的,难道不是么?
但那实在是个大新闻,因为阅读这些领域,学习实际算法,建模和计算结果的方法,记住这些名字都是容易的。在学校里他们教你链式法则,你也能回忆起他们并能运用在考试题上,但有多少学生能真正的了解他们到底意味着什么呢?所以当他们遇到变种的链式问题时,他们就不懂得如何运用公式了。让人感到讽刺的是,了解这是什么比记住如何运用公式更为容易,链式法则仅仅是如何对链式函数求导的意思,函数 f() 引用函数 g() ,你要求导 f(g()),好了,程序员知道所有这些函数相关的;我们每天都使用他们,所以现在比过去在学校更加容易能够想象到问题所在。
这就是为什么我认为他们以错误的方式在教数学。对大多数高中毕业生来说,他们专门教授的内容,不是可以靠经验来证明数学是如何如何有用的,他们教的那些恰恰是非经验式的内容。在你学习如何求导和做积分之前,你将要学习如何计数,怎样编程。
我认为学习数学最好的方法是每天花15到30分钟逛维基百科。那上面有数千数学分支的相关文章。可以从一些你感兴趣的文章着手(比如,弦理论,或者,傅立叶变换,或者张量理论,就是能冲击你相象力的东西) 阅读。如果有什么你不理解的,就去了解那些链接。如此这般直到你累到不行为止。
几个月后,这么做会纵向扩展你的数学知识面,你会发现一些模式,好比,数学的每个分支看上去都包括了一个有着复杂的多元的变量,然后线性代数将会慢慢爬满你的书单列表,直到你强迫自己学会他实际上是怎样工作的,你要下载个电子书或买本书,直到你能从中找到乐趣。
凭借着维基百科,你也能快速的找到一条了解数学基本原理的途径,条条大道通罗马。在某些领域,数学几乎总是形式化我们的“常识”,所以我们能减少或证明那些领域里的新事物。对数学本身的研究就是无止境而且令人着迷的:构造形式模型本质的能力,证明,自明的系统,规则表示,信息,和计算。
符号是个很重大的但很快会令人放弃的东西。数学符号是关闭你通往另一个世界的符咒。即使你熟悉累加,积分,多项式,指数,等等,如果你看到一堆符号堆彻的异常复杂时,你就把他实现的功能简单的当成一个原子操作好了,不要深究太多。
然而,从观察数学来说,尝试着明白人们正在试图解决的问题(那些已被证明了的问题某天也许会对你有实际用途),你会开始在符号中看到相同的类型,你也不再排斥他们。比如,累加符号(大写符号-西格马)或者π(大写符号-pi,连乘符号)起初看上去让人心里没底,即时你了解了他们的基本原理。但如果你是个程序员,你会认识到他仅仅是个循环:一个累加值,一个累乘。积分是一段连续曲线的相加,所以那不会让你郁闷太久。
一旦你习惯了数学的许多分支,和许多不同的符号的格式,你就走在了解许多数学知识的路上了。因为你不再害怕,你将会发现问题,其实他们会自动跳到你面前。“嗨,”你会思索,“我了解这个。这是乘法符号!”
这样你就能扔掉计算器了。有一个充满相象的计算器比如 R,Matlab,Mathematica,甚或是支持向量机的C语言库。但几乎所有有用的数学都是重型自动机,所以你能够让一切都变的自动化。
做题的真正用处
概要:练习的目的在于检测学习成果。
在做了几年的业余数学爱好者之后,你打算做更多的数学,甚至你从没碰过铅笔和纸。比如,你会一直看到多项式,所以最后你会耳濡目染的做起多项式的运算。同样的,对数,根,超越数,和其他到处出现的基本数学原理。
我还是生发了一种感觉,我要亲手做许多的练习题。我正在寻找一种能够跟着证明步骤的方法,比如使用一种“貌似可信的测试”,如果他们的结果看上去或多或少是对的,然后我就会拍拍屁股过去了。但如果我看到的那个证明我听都没听说过,亦或看上去是错的或不可能的情况,我就要挖掘更多的东西了。
这很像读程序源代码,,不是么?当你读某人的代码你不需要手动模拟整个程序状态:如果你知道计算过程大致会发生什么情形,你能靠理智推断出结果。举个例子,如果结果是个列表,他们返回一个标量,可能你会挖的更深一点。但正常情况下你能几乎是以你阅读英文文本的速度(有时仅仅是速度上)扫描源代码,并且你自信你理解了全部状态,与此同时,你也许会发现真正令你震惊的错误。
我认为那就是数学爱好者(数学家和真正的数学迷)怎样读数学论文的,或任何包含了许多数学的论文。他们做了同样的分类检查,正如在你读代码的时候所做的,但不只是这些,除非他们不想把作者的观点扳倒。
照那样说,我会偶尔做做数学练习。如果某些问题(比如代数和线性代数)又不停的跑过来,我就做些练习去确定我是真正的理解她了。
但我要强调这点:不要让练习使你分心。如果一个练习(甚或是一篇特别的文章或章节)开始让你烦恼,那就暂时丢一边继续前进。该跑路就坚决跑路。让你的直觉引导你。你会学的更多,更快,你的信心也会随之增长。
数学如何帮助我们
概要:1.目前的很多热门领域都大量的使用数学。2.作为一种兴趣,数学能够消磨时光,能够给你快乐。
也许不是--不能立刻奏效。但确实能帮助提升你的逻辑推理能力:好比是在体育馆做练习,如果你每天都做一点的话,你整体的能力会得到提升。
对我来说,我已经注意到一些我已经感兴趣的领域(包括人工智能,机器学习,自然语言处理,和模式识别)大量的使用到数学。如我已经挖的有点深度的领域,我已经发现他们使用的数学不再比我在中学的学到的数学还要更难;大部分来说仅仅是不同领域。而不是更难了,并且学习使我能写(或者是在我自己的代码里使用)神经网络,基因算法,贝页斯分类器,集群算法,图像识别,和其他时髦的东西,能产生很酷的应用。我常向我的朋友显宝。
我已经渐渐意识到这点,当别人给我看一篇包含了数学符号的文章我不再像突然冒了一身冷汗:组合,微分,真值表,定列式,无限系列,等等;那些数学符号现在变得容易相处了,但(像编程语言的语法)一开始的话多少还是有点让人感到有些怪异。现在我能更好的理解了,当我一点不知道正在说什么时,也不再感到自己是个不懂数学的人了。因为我知道自己是能够弄明白的。那很好。
我会继续加油做的更好滴。我还有不少活头,有好多书和文章要读。有时我会花整个周末来读数学书,有时会数周都不再思索她。也和其他兴趣一样,如果你单纯的信任她你就会有兴趣,也能更容易的消磨时光,你可以经常一点点的尝试应用你觉得有趣的,并从中获益。
好好学习,天天数学!
出处信息
英文原文:http://steve-yegge.blogspot.com/2006/03/math-for-programmers.html
中英文对照版本:http://www.nowamagic.net/librarys/veda/detail/958
原译者不详
每一节后面的概要,是我加的。
网友评论