程序员的数学修养


1.什么是数学

按照维基百科上的解释,数学没有准确的概念,它可以笼统地分为纯数学和应用数学。纯数学研究数量(Quantity)、结构(Structure)、空间(Space)、变化(Change),使用各种符号找寻规律,将各种猜想形式化,并证明其真伪。数学的基础包括了:数理逻辑、集合论、范畴论、计算理论。数量主要就是数字系统的建立,结构涉及组合、数论、图论、群论、代数等,空间涉及几何、差分几何、拓扑等,变化则是微积分、差分等式、分析。而应用数学则是研究数学问题的解答,于是也可以看作是计算数学,涉及了概率论、统计、密码学、优化、数学经济/物理/化学/生物等。


2.为何要学数学

2.1 你不用知道任何东西

从编程的角度,数学中很多东西的确是没有必要吃苦头去学。在翻译的文章《程序员如何学数学》中,作者戏谑到:“事实上,我觉得你不需要知道任何事情,只要你能保持活着就行了”。个人觉得本文提到的内容是每个程序员应该有的职业素养、科学素养。不管你是在职场做写着你以为普通的代码,还是在学校里做学问,相信用心练习领悟都会受益终身。本文总结了程序员应该关心的数学主要分支和基本的学习方法,但也只能称作数学和数学学习的相关“知识”,真正的修行正如老话所说:“师父领进门,修行在个人”。这些好的书籍、资料顶多只能将你带进数学殿堂的大门内,正式的修行在此才真正开始。

2.2 数学、计算、编程

我们经常说编程的本质是计算,即那本经典的算法书的标题:程序=数据结构+算法。那么数学与计算又是什么关系呢?最近写过一篇《X的奇幻之旅》,是一篇同名书《The Joy of X》的读书笔记。这本书中有一章与全书同名。本以为是全书最核心的一章,结果却什么没学到。

最近一直在思考计算在数学中的位置,突然犹如醍醐灌顶。代数乃至数学中最重要的两个活动:一是定义概念后用等式表示属性(变量)间关系,从而深入了解表示这个概念的数学对象;二是有了概念之后,为其设计计算过程,通常用于解决一个问题。两者都需要证明,前者证明等式所表达关系的正确性,而后者则证明计算过程的正确性。计算过程可以使用前者找到的规律来简化。也许作者并不完全表达相同的意思,但确实给予了灵感。

举个例子,我们提出一个关于数论的概念,比如质数,什么样的数是质数。然后我们研究它、找规律,可能得到一些等式,也比如得到一些结论,比如偶数只有2是质数,并加以证明。最后我们设计一个计算过程,比如计算得到一个区间内的所有质数,于是我们设计一个算法和数据结构。并利用前面找到的规律优化,最后证明其正确性。数学、计算、编程,三者和谐而统一

2.3 天才闪耀时

在上面这一套过程中,计算过程实现后的反复使用,甚至部分推导也许可以用计算机来辅助。但找规律、下结论、设计计算过程、解决问题都是创造性的工作,否则早已被计算机所代替。然而,最展现人类思想伟大的可能要属概念和证明。为什么是这两个呢?

有人说数学是其他学科的基础和指导,比如各种自然科学、经济、工程等等,然而哲学是数学的基础和指导。看起来有点悬,可确实是这样。如果你不相信、不理解无穷的概念,你是不可能建立起微积分的。如果你坚定宇宙是像精密的时钟一样,你是不会相信现代统计学和量子力学的。你要相信,才能创造。这也是最近读了《How Not to Be Wrong: The Power of Mathematical Thinking》的感受。

而证明则是另一种的天才。我们经常习惯去找套路。就像题海战术一样,给不同的解题策略起各种名字。证明也同样有套路,基础就是逻辑和集合论,再加以直接证明、归纳法、反证法等等训练,于是就觉得我们能证明一切。其实,证明或者很多事情有时真的教不了。推荐看看《Proofs from THE BOOK》吧。


3.如何学习数学

3.1 数学家的日常

数学家一般是如何解决问题的呢?首先,我们会从一些公理(Axiom)和定义(Definition)出发,提出猜想和假设(Conjecture),通过中间过渡的引理(Lemma)和命题(Proposition),推导出定理(Theorem),再由此引申出一些推论(Corollary)。以前一直搞不懂这些概念是什么关系,现在终于理清楚了,如上所述顺序就是:Axiom/Definition/Conjecture => Lemma => Proposition => Theorem => Corollary

可能大家对这些概念之间的区别不太了解。从定义上说Proposition是不太重要的定理,其实不必较真,Lemma、Proposition、Theorem、Corollary都是相对来说的,可以自己决定,可能一位数学家觉得这是Lemma另一位就觉得这应该是一条Theorem。比如费马大定理(Fermat’s Last Theorem),其实曾经是一条Conjecture,现在却是Taniyama-Shimura的推论,而名字上却叫做Theorem。

看或者写定义和定理,有一点最重要:最需要留意的其实不是主体,而是条件(Condition)和假设(Assumption)。比如最著名的毕达哥拉斯定理,可能大家都知道两边的平方和等于斜边的平方,但其成立的条件呢?这就好比,我们写代码调用了API时,就想着API的功能,却没留意Precondition,结果API没有返回期望的结果。

3.2 如何读

  • 开始阅读前,先想好想要从这些文字中得到什么:这一点可以说是读任何知识类书籍都必做的一点(除非是随便读来消遣的小说等),比如作为程序员想要从一本数学书里得到什么,哪些最重要,不思考就读甚至不是自己专业的书籍是很容易迷失的。
  • 不要拒绝更高级(经典)的好书,因为每本书的前面几章都会有不错的总结:比如学习微积分,Kline的《Calculus: An Intuitive and Physical Approach》是一本不错的自学入门书,但Spivak的《Calculus》非常经典,只不过据说文字证明都比较严格,对初学者不太友好。但不要轻易地就拒绝一本经典好书,买来看能看懂的部分,比如前面几章关于数字和函数,当作收藏了也不亏(屯书又有了理由:)
  • 仔细看第一章和最后一章,注意经常出现的概念,从而确定主题以及重点。
  • 第一遍初读时跳过复杂的证明,只读定理:但记住证明是数学的核心,之后必须回头看懂证明。
  • 不要轻易地画记号和做笔记,当有了更多理解时再回头标注时会更简练和深刻
  • 主动阅读!被动地读一遍书就像看别人锻炼身体一样,你不会多长一丁点肌肉:当作者说到“很明显”、“通过简单计算就能”、“细节省略、留给读者”时,思考验证作者是否犯错了,不要相信任何看到的东西;做练习!如果你做不出练习,那表示你根本没理解;像下面提到的那样写证明,如果你不能规范地写出来,那也不代表你真的懂了。所以对于经典好书(教科书),比如《Concrete Mathematics》、CLRS、CSAPP、SICP,一定要做好课后习题,有时更有价值的东西甚至会放到习题部分。

3.3 如何写

前面说过写数学的重要性:如果你不能用写的方式解释清楚,那说明你没有理解,写出来才会让你像数学家一样思考。关于如何写数学,第一点就让人很诧异:用自然的语句写出来!这是我们普通人,甚至新手数学家最容易犯错的地方。我们大多数人都以为数学是高度符号化的语言,所以我们用一系列符号来回答解决问题就行了。这样理解不对吗?符号多么简洁、多么高大上,完全用符号来推导不是最好的方式吗?错!符号仅仅是一种速记法,我们想要表述的永远是想法、概念,而没有语句来形成上下文,符号只是一堆没意义的乱码。总而言之,符号只有在语句形成的上下文中才有意义,才能表述概念

自解释代码(self-explaining code):在谈到代码与注释的比例和关系时,我们经常会说到自解释代码,即在最极端的情况下可以做到没有注释,完全通过方法名、变量名达到解释的目的。以前觉得,这种“完美”的情况也许可行,但不完全适用于我们非英语国家的开发人员。但今天在看《How to Think Like a Mathematician》时突然看到这里,不禁陷入深深的思考。纯数学是描述性语言,描述这个世界背后的规律,而程序、算法、计算则可看作应用数学,是过程化语言。证明是纯数学的核心,那么代码(或者算法)就是计算的核心。如果将符号推导与代码做类比的话,那我们是不是可以将证明中的解释语句比作代码中的注释呢?如果这样比较还说得通的话,那是不是可以这样想:连绝顶聪明的数学家都主张在符号中加一些语句,使整个证明更加清楚,那我们普普通通的程序员不应该清清楚楚地写好注释吗,而不是一味的追求代码的自解释。

第二条原则就是:用最简洁的方式写数学。为了达到这个目的,使用尽可能短的单词和语句,避免使用复杂的词汇、句型、双重否定等,这样才能够避免歧义,最容易理解。同时还要清楚地表达自己,像写议论文一样,清楚地列出argument、conclusion,多使用因果关系的连接词。

干净的代码(Clean Code):从这个角度来说,数学证明与计算编程两者有着殊途同归,都强调了用最简洁的符号来表述。在大叔的《Clean Code》中,有专门的章节来强调函数和类都要尽可能地短小。


4.程序员的数学

作为程序员,最熟悉的莫过于离散数学了。从离散而非连续的角度,学习逻辑、集合论、概率统计等。但离散数学的书看多了有时会产生抑制,就会觉得这些都很基础,大概都了解。想要更好地掌握,唯有超越离散数学,往更深的层次去学习。离散数学中的每一个部分都是一个单独的数学分支,都可以继续深入学习。

之前在翻译的文章《程序员如何学数学》中,对原作者“浅尝辄止”的数学学习方法很感兴趣,于是对各个数学分支简单地调查了一下,对其谈到的程序员值得学习的数学分类又补充了一些:

  • 数理逻辑(Mathematical Logic):在知乎一个帖子中看到逻辑分为计算机科学、数学、哲学三个方向,那么我们作为程序员最应该关注的就是离散数学或计算理论中的数理逻辑。
  • 欧氏几何(Euclidean Geometry):经典的欧几里德几何展现了如何从最基本的几条公理,推导出一个系统,与我们构建系统的过程如出一辙。
  • 抽象代数(Abstract Algebra):单从最通用的编程,而非AI、机器学习等专项来说,抽象代数可能是最贴合编程思想的。将数据抽象成抽象结构,再实现操作。重点关注Group Theory、Category Theory等。
  • 数论(Number Theory):数字是一切的基础,而数论就是研究数字中的奥秘。
  • 微积分(Calculus):无所不在的微积分研究万物的变化和累积,对理解算法随输入数据变化的性能变化很有帮助。
  • 概率论(Probability Theory):对现实世界问题的分析离不开概率论,同样对算法行为的分析至为重要。
  • 线性代数(Linear Algebra)
  • 统计学(Statistics)
  • 信息论(Information Theory)

5.学习资料汇总

本文的前半部分只是开胃小菜,真正的修炼从这里才开始。下面就是一些自己精心挑选的参考资料。一部分为科普读物,让你能带着乐趣地对数学的某些方面有一些了解。但千万别以为读了几本科普书,自己无所不能了。看出了乐趣,提高了信心自然好,但要清楚地认识到:任何知识和学科的学习都不简单。所以对每一部分,还需要选一些稍微学术些的课本来深入学习。这一部分是不断更新

5.1 概览

1.《Mathematics: A Very Short Introduction》:牛津出版的一本非常小的口袋书,别看书很小,但内容有口皆碑。
2.《Concepts of Modern Mathematics》:Dover出版,价格公道,作者Ian Stewart是大牛,写过《数学:确定性丧失》和很多数学著作。这本写的也非常深入浅出,不需要什么预备知识就能基本看懂。通过一本书了解数学的发展,而不是我们在学校里学习的传统数学,强力推荐一下!
3.《How to Think Like a Mathematician》:书名有些大,内容可能对于相关专业或有科研背景的人来说太简单,但对于门外汉的程序员来说还是很新奇的,可以学习一下数学方面的人是如何研究问题的。读过之后,再去看编程方面比较严谨的书像《算法导论》,就会有新的发现。

5.2 科普

整理了一下对初学者比较友好的数学书,参考了Goodreads上的评分:

  • 《A Mathematician’s Lament: How School Cheats Us Out of Our Most Fascinating and Imaginative Art Form》
  • 《Flatland》 Edwin A. Abbot
  • 《The Code Book: The Science of Secrecy from Ancient Egypt to Quantum Cryptography》
  • 《The Man Who Knew Infinity: A Life of the Genius Ramanujan》
  • 《The Man Who Loved Only Numbers: The Story of Paul Erdős and the Search for Mathematical Truth》
  • 《Surely You’re Joking, Mr. Feynman!: Adventures of a Curious Character》
  • 《The Joy of X: A Guided Tour of Math, from One to Infinity》
  • 《Journey through Genius: The Great Theorems of Mathematics》
  • 数学史:
    • 《The Math Book: From Pythagoras to the 57th Dimension, 250 Milestones in the History of Mathematics》
    • 《Mathematics: From the Birth of Numbers》
    • 《The Mathematical Experience》
    • 《Men of Mathematics》

5.3 深入

下面是专项训练的书,有些分支还没有选好,先列一下选好的部分:

  • 抽象代数(Abstract Algebra):《A Book of Abstract Algebra》
  • 数论(Number Theory):
  • 微积分(Calculus)
    • 《Calculus: An Intuitive and Physical Approach》
    • 深入学习用Spivak的《Calculus》
  • 概率论(Probability Theory):《Probability and Computing》,深入学习用《Probability Theory: the Logic of Foundation》
  • 线性代数(Linear Algebra):Strang的《Introduction to Linear Algebra》
  • 统计学(Statistics)
  • 信息论(Information Theory)

你可能感兴趣的:(Math)