卡耐基-梅隆大学的编程难题

卡耐基-梅隆大学(CMU)的计算机科学系曾经有一个常规性的小型编程竞赛,参赛对象是刚入学的研究生。竞赛的目的是让这些新的研究人员得到一些关于计算机科学系的直接经验,并让他们展示自己的强大潜力。CMU在计算机领域的研究历史悠久,可以追溯到计算机的先驱时代,它在这个领域所取得的成就可以说是非同凡响。所以对于CMU举办的编程竞赛,其水准可想而知。

比赛的形式每年都不一样,其中有一年非常简单。参赛者必须读入一个文件(文件的内容是一些数值),并打印这些数值的平均值。只有两个规则:

1:程序的运行速度要尽可能的快。

2:程序必须用Pascal或C编写。

参赛选手的程序集中之后由一名系工作人员分批上交。学生们可以自愿上交尽可能多的作品,这可以鼓励非确定性随机算法(就是猜测某些数据集的特征,利用猜测结果获得尽可能快的效率)的使用。决定性的规则是:运行时间最短的程序将获得优胜。 这些研究生们纷纷钻进各个角落,开始折腾各种各样的程序,他们中的绝大多数都准备了3到4个程序参加竞赛。

大多数人都猜想最大的赢家一定采用了代码优化措施,不管是显式地在代码中使用,或是通过正确设置编译器选项隐式地使用。标准的代码优化技巧包括:消除循环、函数代码就地扩展、公共子表达式消除、改进寄存器分配、省略运行时对数组边界的检查、循环不变量代码移动、操作符长度削减(把指数操作转换成乘法操作,把乘法操作转换成一位操作或加法操作)等。

数据文件大约包含了1000个数值,假定读入和处理每个数需要一毫秒(当时的系统差不多就是这个速度)最快的程序也要用10秒左右。

实际结果非常令人吃惊。其中最快的一个程序,操作系统报告用时为-3秒。确实如此——优胜程序的运行时间是负数!第二快的程序大约用了几毫秒,而第三名的作品恰好比预期的10秒稍微好一点。显然,获胜者在编程中做了弊,但他是怎样作弊的呢?评委们在对优胜程序进行仔细审查后,答案揭晓了。

这个运行时间为负的程序充分利用了操作系统。程序员知道进程控制块相对于堆栈底部的存储位置,他用一个指针来访问进程控制块,并用一个非常大的值覆盖“CPU已使用时间”字段。操作系统未曾想到CPU时间会有如此之大,因此错误地以二进制补码方案把这个非常大的数解释为负数。

至于那个费时仅几毫秒的亚军得主同样狡猾,他用的方法有所不同。他使用的是竞争规则而不是怪异的编码。他提交了两个不同的程序,其中一个读入数据,用正常的方法计算机平均值,并将答案写入到一个文件中。第二个程序绝大部分时间处于睡眠状态,它每隔几秒醒来一次检查答案文件是否已存在,如果存在,就打印其结果。第二个程序总共只占用了几毫秒的CPU时间。由于竞赛者允许递交多件作品,所以这个用时极少的程序就把他推上了亚军的位置。

季军作品所花的时间比预期的最小时间还要稍少一些。该程序的构思最为周详,程序员殚精竭虑,用优化机器代码来解决问题,并把指令作为整型数组存储在程序中。由于在程序中覆盖堆栈上的返回地址是非常容易的,所以程序可以跳转到这个整型数组并逐条执行这些指令。所记录的时间如实反映了这些指令解决问题的时间。

当这些策略被揭露后,轰动了全系。有些专家赞成对获胜者进行严厉批评;一群年轻教授则相反,他们建议给他们额外的奖励以表彰他们的天才。最后,双方达成妥协。既没有颁奖,也未对他们进行惩罚,结果不了了之。令人悲哀的是,这个竞赛成了强烈感情的牺牲品。从此以后,这个竞赛再未举行。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值