讨论:写程序到底需不需要懂数学?

本文探讨了数学在程序设计中的重要性,通过具体实例说明如何利用数学知识提高程序效率,并指出数学训练对于成为高水平程序员的价值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

写程序到底需不需要懂数学?

piggy | 08 Jun, 2007 17:26

数学对于程序设计师来说到底重不重要?!类似这样标题的讨论,在网络上已经不知道被讨论多少次了。前两天又在老同事小白的blog上看到了他的看法。以前正方总是喜欢拿算法与效率来表明数学很重要的立场,反方或是最近普遍的观点是要依照需求。两方都没错,我也有一点小心得跟大家分享。

先来谈谈「数学」在大家的心中是长什么样子。我大学时念的是辅大应数,会选应数的原因是一、我的分数上不了资工,二、应数又跟纯数不一样,是比较偏计算机应用的(事实上不是这么回事),应数的全名是应用数学。三、高中时一位要好且计算机很强的同学也是念辅大应数,所以我就这样进了数学系。在一般人眼中是个很硬的科系,那几年全校1/2的名单中,数学系就占了一半。数学系所学的数学,跟一般人所会用到的数学不太一样。除了几门工科必备的微积分、线性代数、机率统计外,剩下的都是高深且抽象的数学理论,像是高等微积分、高等代数、几何学(不是三角形、正方形那种简单几何)、拓扑学等。这几门课程跟本像天书一样,非常的抽象(无法画在直角坐标系上),我能毕业也算是一种奇迹啊~~我真怀疑我那学念到博士班的同学们,他们的脑袋是不是跟我长得不一样。

 
研究所顺利考上的向往已久的资工所,成为名符其实的本科系学生,本以为可以不用再玩数学了,但我发现我错了,是不用再玩那些抽久的高等数学没错,但线性代数、机率统计、离散数学等…用了更多的数学,我想不出来有哪门资工研究所的课没用到数学的。而且你最后的硕士论文要写出来,数学更是不能少的。你以为玩网络不需要数学?大错特错,里面一堆机率统计的东西。电机需要数学吗?当然需要!最基本的傅利叶转换就够搞死你了,所有工科的系所都逃不了数学的魔掌。就算你到了管理学院,会计系要数学、经济系要数学、连心理系有些领域也需要数学。虽然所需要的数学不尽相同,但都在数学的领域里。我开始后悔当年没把数学念好,博士班念到一半念不下去了,其中一个原因是我数学太烂了。

 
写程序需要数学吗?要看程序的目的?那我们就像讨论一个简单的程序,算出1加到100的总和。


完全以程序结果为导向的人,或是训练有素的程序女/男工,甚至有时连我都会很直觉的写出这样的程序:


int sum = 0;

for (int i=1; i<=100; i++)

       sum += i;

上面这个程序片段还算很容易让人一眼就看懂,可是我们明明国中时就学过了这种数列级数的算法了,怎么还会写出上面这么笨的程序呢?


int sum = ((1 + 100) * (100 - 1 + 1)) / 2;或更精简的


int sum = (101 * 100) >> 2;

这个例子已经被说烂了,我们来来看另一个例子,计算1加到10000,奇数和偶数的总和。用循环的话,一样很直觉得就写出来了:

 

int oddSum = 0;

int evenSum = 0;

for (int i=1; i<=10000; i++)

{

       if (i % 2 == 0)

              evenSum += i;

       else

              oddSum += i;

}很简单的程序吧!可是我们稍稍的用我们有12年(国小到高中)的数学背景想一下,你可以写出更精简的程序:

 

int sum = (10001 * 10000) >> 2;

int evenSum = 5001 * 5000;

int oddSum = sum - evenSum;什么?看不懂?!sum应该知道怎么算出来吧?就刚刚第一个例子是1加到100,现在改加到10000而已。evenSum呢?简单的推理一下,1到10000之间的偶数总和是是2+4+6+...+10000,把它们全部除以2的话会变成1+2+3+...+5000,所以1到10000偶数的总和不就是1加到5000的两倍吗?

1加到5000是:

(5001 * 5000) >> 2两倍就不用除那个2了,所以不就是上面那个算式了吗!


那1到10000奇数的总和不就是全部的总和减掉偶数的总合吗!稍微动一下脑袋,可以让你的程序变得很有效率。怕别人看不懂?是不会加个批注在程序代码里面喔!


相信聪明的你,很容易就可以分析出来这两个例子的两种写法,在效能上迶多大的差异,但这不是我在这里想要表答数学是如何如何增加效率的。我想要表答的是,我们明明辛苦了12年,学了一堆的数学,为什么我们要放弃这样的基本训练?我们笑美国人的数学不好,请问你又用了多少的数学来帮助你的生活和你的工作?学了又不用,那不如从小学开始就分科系好了,不喜欢数学、怕数学的,就选完全用不到数学的科系。

 
我今天不是要大家在写程序是时钻研那种算法、功式等,去计较那些在现在动不动在2GHZ, 3GHZ,双核心、四核心之下,所省下的那微小的效率。而是你的态度!你宁愿多打一些code,也不愿动一下脑筋,如果你的态度是这样子的话,那也是活得下去啦,不过你的水平就不过如此而已。

 
你会反驳说,需要用到算法、要讲求效率时,我再去研究一下就好了,干嘛说的很严重似的。今天我们一时兴起,要去爬阳明山,没问题啊,那种程度的山,只要双脚健全走得动的人都能爬。如果换成现在流行的登山步道呢?这需要一点点体力才行。如果你要去爬台湾百岳呢?合欢山的东峰算是最简单的吧?开车到山脚下,穿个好一点的鞋子、好一点的衣服、多一点的体力,也还不是太大的问题。那爬玉山呢?虽然现在爬玉山已经很方便了,连行李都可以请人帮你背,但平常没有一些训练,要爬上去不是那么容易的事。你要站在世界的最高点,去挑战圣母峰,那全世界没几个人办得到,而且办到的人事前可是经过了严格的训练。


你想把自己摆在什么位置?你想要成就到什么样的高度?如果你只想在小小的台湾,在二、三流的公司里,打打项目游击战,赚个还算可以的薪水,那的确,你不怎么需要数学,连软件工程的理论也不太需要,最重要的唬弄客户的技术纯熟就可以了。去年去了101的37楼面试后,我才知道我了不起只爬到阿里山而已,要登上MountainView这座山,我必需十倍努力才行。而这个努力不是我在面试前,看看什么教战手册、写写网络上的考古题我就能够通过的,而是必需把一些数学的训练熟到变成很自然的反应才行。简单的问你就好了啦,上面那个用循环写的1加到10000的那个例子,如果10000改用n的话,那需要多少时间,用大O(big O)来表示。如果你不能很快的推论出是O(n)的话,那你的履历连投都不要投,在37楼问的问题比这难多了,而且你没几分钟的时间可以作答。去年那次,是我第二次后悔当初没把数学学好。


为什么Google会这么重视算法和效率?应该说世界级的大公司都重视,Yahoo、微软、YouTube…,因为你写的程序不是给几十个人、几百个人用而已。而是同一时间有几百万,甚至上千万人使用。一个人慢0.1秒好了,一百万人就10万秒,超过一天耶。浏览一个网页,慢个几秒钟你都不能忍受了,更何况是一天。你说能不计较算法和效率吗?!

 
你想过什么样的生活是你自己决定的,但你想要当个世界级的软件工程师的话,把学数学就当作是一种修行吧!不要怕没地方用,因为你时时刻刻都可以用到它。当你的修行到了某个程度,要挑战高山,就比别人容易多了。

 
好好好,不想深入就算了,但你不觉得放弃12年的数学训练很可惜吗?至少花点脑筋用一下嘛~~,大家都多少用一点,软件的水平就会慢慢提升了,你说是吗?

 
<think>好的,我现在需要帮助用户了解如何阅读和理解用C语言编的大规模项目代码。根据用户提供的引用内容,特别是引用[1]和引用[2],其中提到了词法分析器、编译器的工作原理以及项目结构,我需要结合这些信息来构建回答步骤。 首先,我应该考虑用户的需求:他们可能面对一个庞大的C语言项目,不知道从哪里入手。可能需要从项目结构、代码组织、工具使用、核心模块分析等方面入手。同时,用户提供的引用里提到了词法分析器的实现和编译原理,这可能意味着项目可能与编译器或底层系统相关,所以需要结合这些领域的知识。 接下来,我需要按照系统指令的结构化要求来组织回答,确保步骤清晰,并且每个步骤有具体的建议。同时,必须遵循LaTeX格式的要求,比如行内数学表达式用$...$,独立公式用$$...$$,但在这个问题中可能数学公式较少,但需要注意代码块的正确格式。 然后,生成相关问题,这些问题应该与理解C语言项目相关,可能涉及工具使用、代码分析、调试方法等。 需要检查是否符合中文回答,引用标注是否正确。引用[1]和[2]都与词法分析器和编译器相关,可能在步骤中提到项目结构或模块分析时引用相关内容。例如,在步骤2分析代码结构时,可以引用[1]提到的词法分析阶段的结构,说明实际项目中模块如何划分。或者在步骤3使用工具时,引用[2]提到的跨平台支持,说明工具的选择。 现在,分步骤思考: 1. 了解项目背景和目标:用户需要先知道项目是做什么的,比如是否是编译器、系统工具等。引用[1]讨论的是编译器,所以可能例子中的项目类似,需要明确功能模块。 2. 分析项目结构:查看目录和文件组织,如头文件、源文件、Makefile等。引用[1]提到词法分析阶段的结构,可以类比项目中的模块划分。 3. 使用工具辅助阅读:比如IDE、调试器、静态分析工具。引用[2]提到词法分析器的实验报告和跨平台支持,可能涉及到工具的使用和不同环境下的配置。 4. 跟踪代码执行流程:从main函数开始,了解程序启动流程,结合断点调试。引用[1]中的代码示例可能没有,但编译器的实现通常有明确的执行流程,比如词法分析、语法分析等阶段。 5. 理解核心数据结构和算法:比如编译器中的符号表、语法树等。引用[1]和[2]都涉及词法分析的数据结构,如Token的类型定义。 6. 模块化分析与测试:分模块阅读,如单独分析词法分析部分,参考引用[1]中的实现步骤,可能有助于理解项目中的对应模块。 7. 查阅文档和注释:项目文档和代码注释是关键,引用[2]中的实验报告详细记录了设计思路,类似项目的文档可能提供帮助。 8. 实践与调试:修改代码,添加日志,测试效果。引用[1]提到的错误处理,可能在调试时需要关注。 9. 参考外部资料:比如编译原理书籍,结合引用[1]中的编译原理基础,加深对项目实现的理解。 在生成相关问题的时候,需要围绕理解C项目的方法,可能涉及工具选择、代码结构分析、调试技巧、文档查阅等。 现在需要确保每个步骤中合理插入引用,例如在步骤2提到模块划分时引用[1],在步骤3提到工具时引用[2]的跨平台支持等。同时,保持回答结构清晰,分点说明,使用代码块示例可能的工具命令或代码片段,如使用ctags生成标签,或者调试命令。 最后,检查是否符合所有系统指令,特别是LaTeX格式是否正确,是否有遗漏的引用标注,以及问题的相关性。</think>### 如何阅读和理解C语言编的大规模项目代码 #### 1. **了解项目背景与目标** - **明确功能与领域**:确定项目类型(如编译器、嵌入式系统等),参考项目文档或README。例如,若为编译器项目,需熟悉词法分析、语法分析等阶段[^1]。 - **核心需求与输入输出**:通过文档或示例代码,了解程序的输入(如源代码)和输出(如目标代码或中间表示)。 #### 2. **分析项目结构** - **目录与文件组织**: - 头文件(`.h`):定义数据结构、宏和函数声明。 - 源文件(`.c`):实现具体逻辑。 - 构建脚本(如`Makefile`):了解编译依赖和入口文件。 - 例如,编译器项目中可能包含`lexer/`(词法分析)、`parser/`(语法分析)等子目录。 - **模块划分**:根据功能拆分模块,如引用[1]中词法分析器独立实现,可单独研究其代码。 #### 3. **使用工具辅助阅读** - **IDE与代码索引工具**: - 使用`VS Code`+`C/C++插件`或`CLion`进行代码跳转。 - 生成代码标签:`ctags -R`或`cscope`。 - **静态分析工具**: - `clang-tidy`检查代码规范。 - `Doxygen`生成文档(若项目支持)[^2]。 - **跨平台调试**:如引用[2]提到的工具链,支持Linux/Windows环境调试。 #### 4. **跟踪代码执行流程** - **从`main`函数入手**:定位程序入口,逐步分析初始化过程。 ```c int main(int argc, char *argv[]) { init_lexer(); // 词法分析初始化 parse_input(); return 0; } ``` - **调试与断点**:使用`gdb`设置断点,观察变量变化: ```bash gdb ./project break main run ``` #### 5. **理解核心数据结构和算法** - **数据结构**:如编译器中的`Token`结构体(存储词法单元类型和值): ```c typedef struct { int type; char value[MAX_STR]; } Token; ``` - **关键算法**:如词法分析的状态机实现,或快速排序等算法在项目中的应用。 #### 6. **模块化分析与测试** - **分模块阅读**:以词法分析模块为例,独立编译并测试其功能: ```bash gcc -D TEST_LEXER lexer.c -o lexer_test ./lexer_test < input.c ``` - **单元测试**:若项目包含测试用例,参考`tests/`目录验证模块行为。 #### 7. **查阅文档与注释** - **代码注释**:关注函数头部的功能描述,如引用[2]中实验报告的“设计思路”部分。 - **外部文档**:若项目涉及特定协议(如HTTP),需结合RFC文档理解实现细节。 #### 8. **实践与调试** - **修改与日志**:添加`printf`或日志库输出关键路径信息: ```c void parse_statement() { printf("Parsing statement at line %d\n", current_line); // ... } ``` - **边界条件测试**:例如,输入异常代码观察词法分析器的错误恢复机制[^1]。 #### 9. **参考外部资料** - **书籍与论文**:如《编译原理》(龙书)辅助理解编译器项目。 - **开源项目对比**:对比类似项目(如GCC、LLVM)的实现差异。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值