中国人数学强项与弱项的原因解析
世界人民已经懒得吐槽美国学生的数学水平了,正如他们已习惯于惊叹中国学生的天才。
脱离计算器就不会四则运算,把sinx/n算成“six”,美国学生闹的笑话层出不穷,每隔一段时间,舆论就兴起“救救孩子”的呼吁。相比之下,中国学生的能力之强,令大多数美国中学生咋舌。
网络中广为流传的美国学生在数学试卷上闹出的笑话
中国人的数学为什么好
在经合组织发起的国际学生评估项目(PISA)中,上海的中学生在数学水平测试中超过其他75个城市,排名第一。英国人不胜羡慕,立刻邀请了60名上海中学数学老师赴英介绍经验。
来源:OECD2012年国际学生评估项目(PISA)
另外,其制定的各国家和地区15岁学生数学成绩排名,大陆尚未作为整体参加测试,但中国上海的成绩高居第一,美国只排在36位。
除了日常的教学,竞赛的成绩也体现了这一差距。
国际数学奥林匹克竞赛是面向中学生的最著名竞赛之一,自1985年中国参赛以来,19次获总分第一。中国以外,只有韩国、罗马尼亚、保加利亚和苏联(俄罗斯)、伊朗和美国获得过总分第一,其中,美国仅仅获得过一次。
好事的美国媒体当然会反思。9月份时,《华尔街日报》援引波士顿东北大学和德克萨斯农工大学两位教授的研究成果,将落后的原因归纳为语言问题。
也就是说,中国、日本、韩国、土耳其等国语言带有天然的数学优势,比如汉语,10个基础汉字就能呈现所有数字,而英语却要20个不同的单词,影响了头脑运算效率。
不同语言中,中文、日语、土耳其语都可以运用凑十法表现数字,英语则不能。来源:wsj
运算过程中,“凑十法”(make a ten)的应用与否也影响颇深。就是说,若能将数字首先凑十计算,似乎就更加清晰快速。如“9+5”,用“凑十法”可分解为“9+1”,然后“10+4”,而英语母语者却不能顺畅的将之分解。同样,“11+17”能被中文等换为“10+1+10+7”,“eleven+seventeen”就无法如此。
一些学者也反复思考这一问题,最经典的应当是有怪才之称的马尔科姆•格拉德威尔(Malcolm Gladwell),他在《异类:不一样的成功启示录》一书中以《稻田与数学》为题专门分析研究了中国人的数学为什么特别好这个现象。
格拉德威尔的解释看上去非常有说服力。除了前面提到的10个基础汉字就能呈现所有数字外,他还认为,汉语的单音节使得中国人在处理数字时,心算速度天然会更快;中国人在语言上的另外一个优势是,汉语中表达分数的方式,天然就比其他语言更简洁直观。
但格拉德威尔认为,中国人的数学好,还不仅仅是前述种种语言优势,中国以水稻为主的农业耕作文化具有同样的决定性。因为格拉德威尔注意到,以水稻种植为主的日本、韩国人数学能力同样突出——适宜水稻栽种的地区,农夫一年四季都要忙碌,为了充分利用土地和时间,他们会远比小麦耕作农夫更精打细算。另外,中国古代一直是分散的小农户,经济的独立性,使每个农夫都必须像企业家一样学会计算。漫长历史中的竞争选择,会使得以水稻耕作为主的社会数学能力更为突出。
不过,格拉德威尔的分析虽然头头是道,但无论是他对现象的观察,还是对现象的解释,都有非常严重的错漏。这甚至可能使他的研究变得毫无价值。
中国人的数学好么?
第一个问题是,数学好的标准是什么?
如果我们说某个人群的数学好,指的是数学研究水平,那么问题来了。数学一旦延伸到大学或研究领域,笨笨的美国人立刻站起来了,而中国人的数学优势也神奇地缩小。
世界数学研究中,美国、法国和俄罗斯处于无可争议的领先地位。随后的以色列和日本等国也领先中国。即使是在中学数学向中国取经的英国,数学研究同样大幅领先。如果将话题的讨论范围扩展到研究和应用领域,反而会出现一个新问题,为什么中国人的数学研究不好。
以国际数学奥林匹克竞赛为例,除中国外,1985年以后的许多金牌获奖者们已在国际数学界崭露头角。法国、俄罗斯、美国、匈牙利和巴西等国的竞赛选手们都有获得菲尔兹奖、克雷数学奖等,而中国的参赛者却在研究水平上整体落后于曾经击败过的对手。
美国的数学研究尤其强大,不仅在纯数学领域,物理、化学以及需要大量数学知识的金融学、需要离散数学的基础计算机科学方面也处于领先。美国在这些倚赖数学的领域聚集了大量的人才,其自然科学家和工程师们的整体数学水平也绝不弱于其中国同行。
曾以满分摘得国际数学奥赛金牌的“数学天才”柳智宇(左)现已在龙泉寺出家,法号圣宇
为什么中国在中学数学竞赛中表现得如此出色,但在向后的发展中却后劲不足?
另外一个问题是,如果数学好的标准是中学生数学竞赛水平高,格拉德威尔等人显然忘掉了一段历史,1990年代以前,国际数学奥林匹克竞赛的金牌大户是苏联和东欧国家——国际奥林匹克竞赛原本就是由东欧国家发起,苏联和俄罗斯共获得过16次国际数学奥林匹克竞赛的团体总分第一。
中国在数学竞赛上开始取代苏联和东欧国家,是在苏东剧变之后——就像苏联人不再集中国家一切资源和力量来夺取奥林匹克运动会的金牌后,中国人在奥运会上的金牌开始赶超苏联东欧一样。
苏联人在数学上既没有种种先天的语言优势,也从来没有水稻栽培的历史,更要命的是,俄国和东欧的农夫在西方人看来差不多是世界上最散漫粗放的农夫,他们是离精打细算、勤劳等品质最远的人群。
无论是过去的苏联、东欧,还是今天的中国、日本、韩国等东亚国家,这些初高中数学计算能力较强,并且数学竞赛水平高的地区,唯一的共性就是它们有着强大的国家应试教育*。
实际上,数学竞赛和数学研究有本质区别,初高中的计算能力也与大学数学也并不相同。
同时获过国际数学奥林匹克竞赛金牌和菲尔兹奖的澳大利亚数学家陶哲轩曾在一篇文章中表示:数学竞赛和数学学习非常不同。尤其研究生生涯,学生们不会遇到像数学竞赛题那样描述清晰,步骤固定的题目,尽管竞赛思维在解决研究型问题的某些步骤速度很快,但这无法扩展到更广泛的数学领域,更多问题仍赖于耐心和持久的工作——阅读文献,使用技巧,给问题建模,寻找反例等。
此外,奥林匹克竞赛中的题目虽然难度更大,但考验的是技巧,创造性上要求却更低,但后者是研究领域的核心能力之一。
总得来说,数学竞赛所需的是熟练和技巧,依赖天赋,但依靠大量的集中培训亦可取得成就。而高等数学的研究和学习则靠持久的工作和深入的理解,与技巧性的算术(arithmetics)不同,数学研究讲求抽象化和逻辑推理的使用,对复杂多样的数学问题有深刻理解力远重要于特定类型问题的求解。
著名数学家威廉•瑟斯顿(William Thurston)曾把数学竞赛比作“单词拼写比赛”。他认为,单词拼写比赛获得名次并不代表成为优秀作家,数学竞赛也一样:好成绩不意味着真正理解数学。
数学学习考验的是学习和思考的深度和质量,而数学竞赛需要的是“早熟程度”,要和时间赛跑,要比同龄人学得快。对一个聪明的学生来说,后者更加容易。并且,即使天赋有限,凭借高强度的训练也能在后者取得进步。
显然,东亚的考试型教育能提供最为丰富的训练。行为经济学家尤里•格尼兹(Uri Gneezy)和阿尔多•拉切齐尼(Aldo Rustichini)的实验发现,即使在参赛者水平相仿的情况下,给出单题奖励更高的竞赛能让参赛者获得最好的成绩,这恰恰是中国、东欧等国的强项:更高的竞争压力,更多的竞赛奖励,整个中学教育都以算术能力为培训要点。
这在美国或其他西欧国家所不强求的,对于普通学生,只要达到基本数学成绩即可,如美国马塞诸塞州,统考难度大约是会基本的三角函数运算。
可以说,教育中训练强度的差别造成了普通中学生的数学水平差距。集中培训的强度,也很大程度上影响了竞赛成绩。
那么,进入大学之后,中美数学成绩的差异开始逆转,又是为什么呢?
中国的数学研究为什么不好
或许关键原因是美式的分类教育。美国对普通中学生数学计算能力的基本要求不高,有天赋、感兴趣的学生,则可以在中学里完成大学先修课程(Advanced Placement)。修完AP之后,会参加先修课程考试。
美国中学生的AP教材不仅限于数学,还涵盖多个学科领域
先修课程难度远高于美国普通高中数学,相对于数学竞赛,它的设置更有利于形成对数学问题的理解。比如美国和加拿大的大学先修课程中,微积分部分的两门课程覆盖了一元微积分的所有知识,相当于美国大学两个学期数学课程的内容,通过这些训练能更合理的增进对微积分的理解。而讲求竞赛的中国高中则很少注重这类知识。
从个人未来成长的角度看,提前完成大学先修课程比把时间花在数学竞赛上更合适,前者更接近真正意义上数学研究,基于同样的理由,大学在录取学生的时候也会把先修课程的成绩作为一项重要的考量。
至于研究领域,高强度数学计算训练的效用非常低。现代数学和很多基础学科一样,延续的研究传统和学派氛围,往往决定了其成就的高低。在这一点上,中国大学与欧美大学存在巨大落差。
而苏联和东欧国家竞赛成绩也曾非常出色,但同时又是数学研究最顶尖的国家——过去近100年中,苏联-俄罗斯一直都是数学研究最顶尖的国家,是公认的和美国及法国齐名的数学研究大国。它与中国的强烈反差,恰好也是这个原因。
苏联(俄罗斯)优秀而悠久的数学研究传统几乎从未中断过。早在18世纪,近代数学先驱莱昂哈德•欧拉在彼得堡工作了30多年,带动了俄国著名的彼得堡数学学派。此后,俄国和苏联又涌现出了罗巴切夫斯基、切比雪夫、李亚普诺夫和马尔科夫等数学家。
政治最动荡的斯大林和赫鲁晓夫年代,苏联的数学研究传统也没有中断,相反,因为战争和计划经济的需要,数学家们逃过了政治运动冲击。不但生活上有相当保障,且能有做感兴趣研究的相对*。
1950年代末期,摄影家埃里希·莱辛生镜头下的苏联中学生在上数学课
同时,他们还有着特色的讨论班体系——由知名数学家主持,不限年龄和资历,感兴趣者均可参与。这非常有助于传统的延续。苏联的讨论班中涌现了一大批年轻数学家,形成了著名的莫斯科学派。
在培养更年轻的数学人才方面,苏联也与中国不同。苏联和中国同样有大量的数学夏令营,但苏联夏令营依靠兴趣报名,不强调考试和分数。讲课的是往往是某领域的大师,而不是专注于训练学生考试的中学老师。比如柯尔莫哥洛夫等最顶尖的数学家,每年都会参加中学数学夏令营。这不但可让学生对数学产生兴趣,且能让有天赋的学生有机会与大师对话,尽早了解真正意义上的数学。
此外,苏联数学界一直和国际数学界保持联系。当时极为繁荣的法国布尔巴基数学学派在苏联很受欢迎。苏联数学界翻译国际数学著作的速度也是一绝。
相比之下,同时代的中国数学家则凄惨的多。即使能逃过死亡,也只能按领导的安排作研究。例如,著名的解析数论学家华罗庚归国不到两年不堪其辱,但自杀未遂。此后不得不研究和推广指导“蒸馒头”的优选法。而华罗庚的老师,清华大学数学系的创始人熊庆来则直接*害致死。
1974年冬,华罗庚在广西深入车间讲解优选法
而中国的学生也难说幸运。他们过早的接受了高强度训练,虽得到竞赛金牌,但前方并没有开放的高等教育氛围和连续的数学传统,让他们当中有真正天赋的人在研究领域绽放光彩。当然,好的竞赛成绩,可让他们进入一流大学,可让学校领导评上先进,甚至对国家也不坏——将来这些学生留学美国,会让美国人感慨,中国人的数学计算能力真强啊。
转载:https://yq.aliyun.com/articles/646972?spm=a2c4e.11153940.0.0.1be4ef8cUcYFzf
推荐阅读
-
中国人数学强项与弱项的原因解析
-
F#探险之旅(二):函数式编程(上)-函数式编程范式简介 F#主要支持三种编程范式:函数式编程(Functional Programming,FP)、命令式编程(Imperative Programming)和面向对象(Object-Oriented,OO)的编程。回顾它们的历史,FP是最早的一种范式,第一种FP语言是IPL,产生于1955年,大约在Fortran一年之前。第二种FP语言是Lisp,产生于1958,早于Cobol一年。Fortan和Cobol都是命令式编程语言,它们在科学和商业领域的迅速成功使得命令式编程在30多年的时间里独领风骚。而产生于1970年代的面向对象编程则不断成熟,至今已是最流行的编程范式。有道是“*代有语言出,各领风骚数十年”。 尽管强大的FP语言(SML,Ocaml,Haskell及Clean等)和类FP语言(APL和Lisp是现实世界中最成功的两个)在1950年代就不断发展,FP仍停留在学院派的“象牙塔”里;而命令式编程和面向对象编程则分别凭着在商业领域和企业级应用的需要占据领先。今天,FP的潜力终被认识——它是用来解决更复杂的问题的(当然更简单的问题也不在话下)。 纯粹的FP将程序看作是接受参数并返回值的函数的集合,它不允许有副作用(side effect,即改变了状态),使用递归而不是循环进行迭代。FP中的函数很像数学中的函数,它们都不改变程序的状态。举个简单的例子,一旦将一个值赋给一个标识符,它就不会改变了,函数不改变参数的值,返回值是全新的值。 FP的数学基础使得它很是优雅,FP的程序看起来往往简洁、漂亮。但它无状态和递归的天性使得它在处理很多通用的编程任务时没有其它的编程范式来得方便。但对F#来说这不是问题,它的优势之一就是融合了多种编程范式,允许开发人员按照需要采用最好的范式。 关于FP的更多内容建议阅读一下这篇文章:Why Functional Programming Matters(中文版)。F#中的函数式编程 从现在开始,我将对F#中FP相关的主要语言结构逐一进行介绍。标识符(Identifier) 在F#中,我们通过标识符给值(value)取名字,这样就可以在后面的程序中引用它。通过关键字let定义标识符,如: let x = 42 这看起来像命令式编程语言中的赋值语句,两者有着关键的不同。在纯粹的FP中,一旦值赋给了标识符就不能改变了,这也是把它称为标识符而非变量(variable)的原因。另外,在某些条件下,我们可以重定义标识符;在F#的命令式编程范式下,在某些条件下标识符的值是可以修改的。 标识符也可用于引用函数,在F#中函数本质上也是值。也就是说,F#中没有真正的函数名和参数名的概念,它们都是标识符。定义函数的方式与定义值是类似的,只是会有额外的标识符表示参数: let add x y = x + y 这里共有三个标识符,add表示函数名,x和y表示它的参数。关键字和保留字关键字是指语言中一些标记,它们被编译器保留作特殊之用。在F#中,不能用作标识符或类型的名称(后面会讨论“定义类型”)。它们是: abstract and as asr assert begin class default delegate do donedowncast downto elif else end exception extern false finally forfun function if in inherit inline interface internal land lazy letlor lsr lxor match member mod module mutable namespace new nullof open or override private public rec return sig static structthen to true try type upcast use val void when while with yield 保留字是指当前还不是关键字,但被F#保留做将来之用。可以用它们来定义标识符或类型名称,但编译器会报告一个警告。如果你在意程序与未来版本编译器的兼容性,最好不要使用。它们是: atomic break checked component const constraint constructor continue eager event external fixed functor global include method mixinobject parallel process protected pure sealed trait virtual volatile 文字值(Literals) 文字值表示常数值,在构建计算代码块时很有用,F#提供了丰富的文字值集。与C#类似,这些文字值包括了常见的字符串、字符、布尔值、整型数、浮点数等,在此不再赘述,详细信息请查看F#手册。 与C#一样,F#中的字符串常量表示也有两种方式。一是常规字符串(regular string),其中可包含转义字符;二是逐字字符串(verbatim string),其中的(")被看作是常规的字符,而两个双引号作为双引号的转义表示。下面这个简单的例子演示了常见的文字常量表示: let message = "Hello World"r"n!" // 常规字符串let dir = @"C:"FS"FP" // 逐字字符串let bytes = "bytes"B // byte 数组let xA = 0xFFy // sbyte, 16进制表示let xB = 0o777un // unsigned native-sized integer,8进制表示let print x = printfn "%A" xlet main = print message; print dir; print bytes; print xA; print xB; main Printf函数通过F#的反射机制和.NET的ToString方法来解析“%A”模式,适用于任何类型的值,也可以通过F#中的print_any和print_to_string函数来完成类似的功能。值和函数(Values and Functions) 在F#中函数也是值,F#处理它们的语法也是类似的。 let n = 10let add a b = a + blet addFour = add 4let result = addFour n printfn "result = %i" result 可以看到定义值n和函数add的语法很类似,只不过add还有两个参数。对于add来说a + b的值自动作为其返回值,也就是说在F#中我们不需要显式地为函数定义返回值。对于函数addFour来说,它定义在add的基础上,它只向add传递了一个参数,这样对于不同的参数addFour将返回不同的值。考虑数学中的函数概念,F(x, y) = x + y,G(y) = F(4, y),实际上G(y) = 4 + y,G也是一个函数,它接收一个参数,这个地方是不是很类似?这种只向函数传递部分参数的特性称为函数的柯里化(curried function)。 当然对某些函数来说,传递部分参数是无意义的,此时需要强制提供所有参数,可是将参数括起来,将它们转换为元组(tuple)。下面的例子将不能编译通过: let sub(a, b) = a - blet subFour = sub 4 必须为sub提供两个参数,如sub(4, 5),这样就很像C#中的方法调用了。 对于这两种方式来说,前者具有更高的灵活性,一般可优先考虑。 如果函数的计算过程中需要定义一些中间值,我们应当将这些行进行缩进: let halfWay a b = let dif = b - a let mid = dif / 2 mid + a 需要注意的是,缩进时要用空格而不是Tab,如果你不想每次都按几次空格键,可以在VS中设置,将Tab字符自动转换为空格;虽然缩进的字符数没有限制,但一般建议用4个空格。而且此时一定要用在文件开头添加#light指令。作用域(Scope)作用域是编程语言中的一个重要的概念,它表示在何处可以访问(使用)一个标识符或类型。所有标识符,不管是函数还是值,其作用域都从其声明处开始,结束自其所处的代码块。对于一个处于最顶层的标识符而言,一旦为其赋值,它的值就不能修改或重定义了。标识符在定义之后才能使用,这意味着在定义过程中不能使用自身的值。 let defineMessage = let message = "Help me" print_endline message // error 对于在函数内部定义的标识符,一般而言,它们的作用域会到函数的结束处。 但可使用let关键字重定义它们,有时这会很有用,对于某些函数来说,计算过程涉及多个中间值,因为值是不可修改的,所以我们就需要定义多个标识符,这就要求我们去维护这些标识符的名称,其实是没必要的,这时可以使用重定义标识符。但这并不同于可以修改标识符的值。你甚至可以修改标识符的类型,但F#仍能确保类型安全。所谓类型安全,其基本意义是F#会避免对值的错误操作,比如我们不能像对待字符串那样对待整数。这个跟C#也是类似的。 let changeType = let x = 1 let x = "change me" let x = x + 1 print_string x 在本例的函数中,第一行和第二行都没问题,第三行就有问题了,在重定义x的时候,赋给它的值是x + 1,而x是字符串,与1相加在F#中是非法的。 另外,如果在嵌套函数中重定义标识符就更有趣了。 let printMessages = let message = "fun value" printfn "%s" message; let innerFun = let message = "inner fun value" printfn "%s" message innerFun printfn "%s" message printMessages 打印结果: fun value inner fun valuefun value 最后一次不是inner fun value,因为在innerFun仅仅将值重新绑定而不是赋值,其有效范围仅仅在innerFun内部。递归(Recursion)递归是编程中的一个极为重要的概念,它表示函数通过自身进行定义,亦即在定义处调用自身。在FP中常用于表达命令式编程的循环。很多人认为使用递归表示的算法要比循环更易理解。 使用rec关键字进行递归函数的定义。看下面的计算阶乘的函数: let rec factorial x = match x with | x when x < 0 -> failwith "value must be greater than or equal to 0" | 0 -> 1 | x -> x * factorial(x - 1) 这里使用了模式匹配(F#的一个很棒的特性),其C#版本为: public static long Factorial(int n) { if (n < 0) { throw new ArgumentOutOfRangeException("value must be greater than or equal to 0"); } if (n == 0) { return 1; } return n * Factorial (n - 1); } 递归在解决阶乘、Fibonacci数列这样的问题时尤为适合。但使用的时候要当心,可能会写出不能终止的递归。匿名函数(Anonymous Function) 定义函数的时候F#提供了第二种方式:使用关键字fun。有时我们没必要给函数起名,这种函数就是所谓的匿名函数,有时称为lambda函数,这也是C#3.0的一个新特性。比如有的函数仅仅作为一个参数传给另一个函数,通常就不需要起名。在后面的“列表”一节中你会看到这样的例子。除了fun,我们还可以使用function关键字定义匿名函数,它们的区别在于后者可以使用模式匹配(本文后面将做介绍)特性。看下面的例子: let x = (fun x y -> x + y) 1 2let x1 = (function x -> function y -> x + y) 1 2let x2 = (function (x, y) -> x + y) (1, 2) 我们可优先考虑fun,因为它更为紧凑,在F#类库中你能看到很多这样的例子。 注意:本文中的代码均在F# 1.9.4.17版本下编写,在F# CTP 1.9.6.0版本下可能不能通过编译。 F#系列随笔索引页面