在知乎上面看到了一篇博文,感觉很有意思。传送门:http://www.yinwang.org/blog-cn/2015/07/04/math
特别是初学者看了之后,容易产生共鸣,认为数学这个东西就不好了、不重要了或者说不认真学数学了。然后对数学产生逆反心理(逃
所以我把这篇博文po出来,希望能够让大佬们发表下对于数学与编程的关系的看法。(虽然知乎上很多类似的回答了,但想听听大家的意见)
数学与编程
Moenya 我又来吹Haskell了
iosmanthus 大佬,关于Haskell的数学有谁懂??
Moenya Yin Wang这篇文章的事实基本都对,然而结论是错误的。事实:计算机的基础不是数学、数学的语言异常糟糕、编程是艺术,甚至可以包括数学家写不出好的代码。结论:能写出好程序的人,却能更好的理解数学。我建议你们先学编程,再去看数学。
什么是“能写出好程序的人”,如何评价所谓的“好”,在这个“好”之前一点数学都不需要读?没有一点数学基础,恐怕编程也编不出来吧,更不要说编出好程序了。
学数学可以是一个漫长、反复迭代的过程。现在大学的教学计划基本没有多大的错,而且就算错了你也必须跟着,跟着学就好了。如果在大学这一点点的“信任”都不存在,那么其实这样的大学本身也没有多大用,既然都没多大用,纠结什么?该干啥干啥。
关于数学我说过很多,到目前我依然在修正自己的看法。比如,以前我很喜欢推荐大家看数学的科普,提升学习兴趣从而得到更好的学习数学的效果。现在我有点反对科普,因为科普里面的为了所谓的兴趣牺牲了大量的准确性,而且指导性也不强。不如拿起一本书开啃。有人说,没兴趣怎么学得下?其实这是自欺欺人的说法,说得好像自己对高考很有兴趣一样。你反驳说,不对啊,高考是没办法。是的,学数学就是这样,不受点苦根本没办法提高。没办法!
现在我对年轻朋友说,你们不要学太多数学,他们都会反对我。没办法,不学没办法高考;没办法,不学进不去腾讯、阿里。我说不要学太多,主要是因为他们太多的数学学习根本就是无效学习,没有任何指导性,自己都不知道自己干啥,还自我欺骗说,啊,以后就有用了,以后会有用的。我看大多数人都用不上,或者用上的都是trivial得不得了的一点东西,那点东西还值得苦读吗?
编程跟数学的关系大概就是java与JavaScript的关系吧。为什么一定要有关系呢?关系尚未发生岂不更是真爱?看来Wang Yin连问题都提错了。
- 已编辑
Bintou 我不懂 ? 知道的仅局限于他Haskell Book第一章介绍的那一点lambda calculus
我不知道,在Yin Wang的眼中Lambda那点东西是否算数学?不过,说白了Lambda与编程也没多大的关系,虽然它是PLT(程序语言理论)的基础。照推算,他应该是认为Lambda不是数学吧,否则结论就有问题了。
- 已编辑
曾经也在这个话题迷茫过,那时候没找到一个能让自己信服的答案,我也一直都比较倾向于自下而上的归纳,更喜欢接地气一些的观点。大一大二那时候在学校关于数学只看到 Bintou 老师的观点,和我那时候的认知还不太接轨,性格使然,不习惯主动地追问,所以也是一直比较迷。后来反复看了一个关于数学与模式的话题的演讲,才慢慢打开思维,后知后觉,也在这里留下我关于这个话题的一些感悟吧。
以我目前的了解来看,在用编程的手段解决问题的这个领域,数学更多的是以一种工具的角色而存在。数学的规律可以作为一种依托,指导问题解决方案的设计过程,某些时候可以大大节约机器乃至于人力层面的投入和成本的消耗。
从这个角度出发的例子很多,比如说二分查找法,依托的是排列的顺序的关系。图书馆的书架的书按照顺序排列,按照索书号找书的过程,不知不觉也是用到这样的规律,因为是从小到大排列,当我们来到某个书架,随便看一本书,比较索书号的大小,然后就能确定下一步寻找的方向,这时候可以瞬间排除掉一大半的书,快速找到想要的。那些乱放书的人,也正是破坏了这一层面的数学关系,导致找书的人需要重新按顺序“遍历”。这里节省的时间,也是利用好数学带来的收益。
网易公开课有一门CS50的课程,第一课以一种可以给你带来惊喜的方式去演绎二分查找,推荐一看(曾经有水过一帖)。
现在通行的计算机的结构里面,硬件对软件提供了按地址访问存储单元的模型。类似图书馆书架中的书的排列,存储单元也是按一种顺序的关系来排列的。自然而然,我可以从这一大堆存储单元里,划定其中一部分为我所用,记住第一个地址,然后以第一个地址为基准 +0,+1,+2 ... +n (也就是 + 下标)计算出每一个单元的地址,就能按下标去读取某种东西,这样的模式总结起来,就有了“数组”这种基本的数据结构。
基于现实提供的这个基本结构,我们可以从中构建出各种各样的花样(这里的说明仅仅是为了建立大体印象,忽略了一些细节)。
比如说要把一堆数据构成一个“二叉树”。
这里的目标是,利用上面所说的硬件提供的基本能力,通过特定的安排,使它能存储“二叉树”的基本结构,下面是实现存储的思路:
二叉树每一个节点都应包含三重信息:
- 节点保存的数据;
- 左子节点;
- 右子节点。
在现有的按地址访问的硬件中,我们要表示二叉树这种结构,自然也是,通过地址找到节点存储的位置,然后通过这个节点包含的左右子节点的地址来访问对应的左右子节点。
在具体实现中,最容易想到的方法是,分别为每一个节点开三块空间。用 C 语言的结构体表示如下:
struct node {
int data; // 数据
struct node *left; // 左子节点地址
struct node *right; // 右子节点地址
};
这里为了维护这种节点和节点之间的联系,多花了一些存储空间去保存目标节点的地址。有时候我们要求很苛刻,不想多花一点空间在额外的东西上面,有没有什么办法呢?还真有!
留意到每个节点的编号,和左右子树的编号。花点心思去观察一下,可以发现一个规律:
从上到下,从左到右编号,假设某个节点的编号为 n,那么它的左子节点的编号为 2 * n,右子节点为 2 * n + 1。
确认这个规律是正确的话,这里的节点和左右子节点在编号上就出现了一种“天然的”数学上的联系。恰好我们的内存地址也是这样的按顺序的编号。那么,我们可以把这里的规律利用起来。此时,我们就把节点和左右子节点之间的联系依托给了数学,在无形中形成的节点间的关系,就不用依赖于给每一个节点的子节点多预留的的存储空间了。只需简单地利用这里的规律计算一下下一个节点的地址,甚至还能少一个读取地址的过程。
当然,把这里的关系依托给数学也会带来一些缺陷,假设这棵二叉树不完整,地址还是预留了,部分空间没有利用起来,当这颗树变得复杂,有些空间就浪费了。所以说,具体如何选用,是通过存储空间来建立联系,还是利用本身存在的数学联系,得看具体的需求。
通过数学有时候可以把一些难以完成的事情变得简单,最近搬砖写网页也常用到一些平移,旋转之类的变换,其中的内部实现也利用了很多数学的规律。通过线性代数的矩阵的变换的角度,图形的变换通过矩阵描述,需要应用多个变换时,我们可以事先通过矩阵乘法把变换合成起来再使用,就能一次将多个变换作用到目标上。
参考这些文章:
二维图形基本几何变换矩阵 - 姜希成的博客 - CSDN博客
旋转变换(一)旋转矩阵 - Frank的专栏 - CSDN博客
浏览器解析网页,生成出来的交给 绘图引擎 的指令,也有变换矩阵的存在
借助线性代数的规律,我们可以去操作许多难以建立直观,甚至根本建立不了直观的东西。
吴军的《数学之美》的开头有篇推荐语提到,牛顿的《自然哲学的数学原理》提到了一种简单性的法则:
法则1:除那些真实而已足够说明其现象着外,不必去寻求自然界事物的其他原因
数学在探索现实中抽象出来的规律的各种可能性,编程是在尝试把现实中的问题抽象到能适应现有的机制的手段来解决,强调更多的是实现这一层。数学本身也是融合在了我们行动的方方面面,无论是写什么代码,或多或少都会涉及到数学。
觉得,对于程序员来说,学习数学的着重点主要在于“可以干什么,怎么做”,了解“为什么”的目的也是为了更好地去完成某些事情。更深入的“为什么”,在其中玩出花样,应该是数学相关专业的人们着重做的。
能对这种观念产生共鸣的人应该本身就不喜欢数学或者说数学思维能力就不强吧,那他们以后从事的方向大概就与数学无缘了,IT行业除数学外的需求也挺多的啊。但是某些方向比如图形学基本就是在用代码实现数学公式,还有密码学等等,数学不行是干不了这些活的。所以我觉得这个问题答案很明显/滑稽。
- 已编辑
Doc 数学存在于方方面面,怎么可能没缘分呢,深入了之后肯定也是绕不开数学。人也是不断发展的,发展方向刻意地避开数学,更可能的是这种“数学很差”的标签贴在了这个人的身上,然后没挣脱出来甚至没意识到这里的束缚所在。
这一点可以从《学习之道》里看出,作者最初并不是搞数学的,后来还是成了工程学教授。
芭芭拉•奥克利(Barbara Oakley)
现为工程学教授,本科专业(居然是)俄语。
小学到高中数理成绩一路垫底,因此热爱文学。职场生活,不得不学习大量新鲜知识,甚至是头疼的数学知识。放下工作,回到学校,竟然学成了工程学博士,后留任教授。在MOOC、Coursera上开创最受欢迎的学习课“learning how to learn”,数十万人报名。
本书一出版即高居美国亚马逊学习类图书榜首,是一本学习神书,看过的人秒变“学霸体质”,开启外挂模式。
大概是,靠着一股强大的外力突破了内心的壁障。
0x0001 把《什么是数学》这本书找了出来,它在序言里其实很好地说明了数学与其他东西的关系。
比如第一版序言,他强调学习数学主要是用来锻炼思维的,数学是科学思考与行动的基础。
就如bintou老师说的,数学类的科普性读物确实可以激发一定的兴趣,但丢失了数学的准确严谨,不得不说是对数学实质的损害。作者过分强调了兴趣的重要性。
身为学生,我认为我们没有资格怀疑老师的教学方案,说什么教条主义都是虚的,是借口,该刷题就刷,谁说刷题刷不出独立思考的能力、刷不出解决问题的方法。
事实上,很多高数的内容确实是难以联系到生活中的(我的理解),要激发对数学的学习“兴趣”,应该联系到专业上面,有一种鞭策的力量(这也许是一种“不得不”的妥协,但事实就是这样)。比如有时候敲代码的时候会涉及到比较高深的数学知识,没有相应的数学知识储备,代码要怎么敲。
第一版的序言中,感觉就是在否定或者说批判当时的数学教育,故意把学习数学兴趣大于学习数学知识本身。这可以理解,毕竟作者是科普书的作者,不可否认的是,类似的科普书确实可以激发兴趣,然而就像这个
数学知识概念本身就是我们认知数学的工具。
在对第一版修正版的序言中,作者呼吁要超越形式主义,把握住数学的实质:
第二版的序言,作者真正解释了什么是数学,并且反驳了一种思想:
(其实在后文介绍数学的历史中,又扯到了形而上学。不过这里是序言,就直说序言里的东西。)
是不是有一种,数学太伟大了这样的想法。
从这个意义上,这本书无疑是成功的,它成功激起了读者的阅读兴趣。
总结起来,不要说什么学习数学的兴趣,这其实是一种妥协,你不得不去学。它就是很多东西的基础,你从中学到的不仅仅是做题、概念、定理、公式,更是思维方式。
尽管可能有些消极,但我认为现实如此。
Moenya 感受到了一种阅读经典带来的力量
南大的“悦读经典计划”这个网站是2014年开的,现在是2019年,还是很有意思啊!
http://njdxydjd.mh.libsou.com/
- 已编辑
最近我沿着王垠的提示(特别是Frege逻辑)读了一些数学的内容,有了一些新的想法。
首先王垠指的不是数学工具与编程语言的直接对应关系,这涉及人们对数学不同看法,从我的关注点出发理解(也是猜)他指的是数学工具的目的(达到某种思维训练,建立判断力/直觉)与编程语言设计之间的关系。
举个不太恰当的例子,null类型在不同编程语言中的实现,在Ruby里面的nil有一个专门的NilClass,R里则是它自己,Java(可能还有其他C类语言)都是不作为任何类/对象的,这个问题和集合论的关系是数学和程序设计问题的重要关注点。
最近我读了几页Kolmogorov的Elements of the Theory of Functions and Functional Analysis,这种数学系学生看的书竟然还能读懂一部分,对于空集的论述,他的说法让我有点惊讶,大意是“空集的设置主要目的是考虑到有时候不清楚集合中是否存在元素的情况”。
同时我找到了Alonzo Church(lambda calculus发明者)的的Introduction to Mathematical Logic,序言部分赫然写着我之前读过所有数学逻辑等方面的书没有强调的内容:Name和Sense的区分,具体内容不复述了,但结合Gottlob Frege在Begriffsschrift前面对于逻辑的定义,以及他回应罗素悖论的内容https://edisciplinas.usp.br/mod/resource/view.php?id=2261850 一个共性的东西可以理解:逻辑是一个模型,而且不保证是“完全模型”。朴素集合论出问题是人们探索能描述整个宇宙的模型之一,出问题太正常了,胜败乃兵家常事。
我对现代概率论的基础测度论早有心仪,顺着Kolmogorov的书搜到了奠基人Maurice Frechet的一些内容,经他人转述,In his thesis Fréchet defines a metric space or class (D) as a class of elements, the relations among which are established by means of a function of pairs of elements of this class
(https://www.ams.org/journals/tran/1927-029-03/S0002-9947-1927-1501402-2/S0002-9947-1927-1501402-2.pdf)
Frege的集合/逻辑思想通过他给罗素的回信中可窥见一些,很惭愧大意还没完全看懂,但关键词也是class和object。
类别class和object的关系在编程语言中的意义,这些也都是探索中的模型。
Niklaus Wirth在代表作Algorithms+Data Structures = Programs (也是刚借到的书)里指出编程语言是对能理解这个语言的计算机的抽象。换句话说,计算机(连同编程语言;或者说编程语言基础上的计算机)也是对计算的一个探索和发展,这跟数学有极大重合。
然而一般意义上的数学没有假设计算机这种自动化设备的存在。参考A method of programming, Dijkstra关于一般自动设备(比如60年代的咖啡机)和计算机,根本区别在于计算机programmable可编程,确切说是可以自由无限编程,摆脱了特定硬件束缚,根本原因在于形式语言的发展为计算提供了一个普遍的可拓展方案。而数学没有这么一个体系化的内容。
你看许多极其复杂的计算都通过算法实现了,人们争相阅读Scikit-learn(一个Python机器学习库)来研究那些天书般的数学是如何在计算机上实现的。我最初看到牛顿法求解方程时候觉得挺奇怪的,因为有种计算机计算不是直接套公式,而是追求数值方法(迫近)的感觉。
现在我觉得之所以有种种疑惑和纠结是因为数学学习的目的没有明晰,数学为了是培养思维、建立理性直觉的,而绝大部分数学教程和学习资源都是强调工具本身。
如王垠所说,也许从古至今都是这样,有知识的人喜欢把知识垄断,让没知识的人知其然而不知其所以然。让他们去套用我们想出来的公式和定理,证明给他们看这些是正确的。但是不要告诉他们这些公式和定理是怎么想出来的,不要把知识的“生产工具”给他们。这样这些人就不可能想出跟我们同样水准的公式,就会把我们当成“天才”供养起来。
(https://github.com/AlexiaChen/YinWangBak/blob/master/%E8%AE%BA%E7%A0%94%E7%A9%B6.md)
从刚才谈测度论第三个基本公理(三角公理)的文章开头(虽然后面看不懂,也不看了)很清楚理解到,Frechet建立测度论的根本不是为了研究某个特定空间(比如实轴[0,1],表面上这就是概率论的话题)而且为了提供一个研究各种空间内(各种class)拓扑关系(具体而言是点拓扑,而他对“点”也建立了严密的定律值得一看)的普遍方案,这个方案基于3条公理,正如欧氏几何的公理一样。
从数理逻辑和测度论的经典著作序言或概要文章我们可以很清楚认识到这个观点:真正好的学习是学习“道”/思维。数学学习和编程学习都是要为了培养独立探索模型化和分析事物的能力的,至于那些具体分支、符号都是工具。
然而数学本身的符号体系(广义的)如王垠所说非常糟糕,这种糟糕严重干扰了它模型化世界的初衷,人们纠结各种细节、符号含义而无法专注于背后的思维。程序语言/计算机多大程度基于数学而产生我无从探讨,但它肯定现在由于数学符合的混杂晦涩和计算机硬件(电路)的特征走上了“迭代式”构建的道路,反而突破了数学沉沉相因的困境。
数学计算实现大多数都是数值方法,之前看到的一点资料显示R的C底层是这样的,「Matlab应该也是但它闭源」,这本身就可能是对“精确数学”范式的挑战,跟号2的1.41421...到底区别是什么,计算机由于硬件局限经常高度迫近0但无法达到准确的0,这种区别在计算机时代有和意义,这都值得探索。
大多数学生应该都会对数学符号感到头疼,程度不一样但绝对极少有喜欢这种繁复的,相比之下程序语言非常有限的关键词(C类语言20多个,极端的COBOL300多但也比现有数学概念少得多了)加上运算符就能几乎计算一切,这难道不是一个突破吗?
也许数学的真谛——宇宙规律有很多种描述方法,现有数学也好,另辟奚径的程序语言也好都是实现方式。
刚才我在搜索“通过编程来理解数学概念”(不是单纯学习使用数学工具)结果重温了这个帖子。The Haskell Road绝对是好的尝试,但是它也只探索到初级的微积分。
ps 学习内容方面,真的要看大师原著,测度论祖师爷的Invitation to Combinatorial Topology才100多页「组合拓扑在计算机图像等领域非常重要」,基本问题都点到了而且“力求高中毕业生能读懂”,深入浅出不是一句空话,很多高深莫测的理论都根植于高中生能理解的生活现象/常识中。