这次也是做 Numerical Analysis 的作业出现的问题了。按照惯例,是学生提供一个函数,让 OJ 的 main 函数来调用,得到结果。这次是迭代取得矩阵最大特征值的题目,那个被调用的函数中传递进来一个二维数组 a 用来表示矩阵。
用的方法是 shifted inverse power method ,中间要解的方程组矩阵和 a 有一些区别,我以为 a 在每次传递进来之后会被 main 函数重新从 input.txt 读取数据覆盖掉,既然如此,就直接修改 a 算了,也是为了空间占用更少一点。
可是得到的程序一直是 Wrong Answer ,很郁闷,于是就睡觉去了。今天早上起来,仔细检查了一下,发现端倪就出现在这里:main 函数其实有可能会用好几次 a ,因为它会针对同样的 a 用不同的初值传递过来计算,几次调用过来,a 被我修改了好几次,便面目全非了。我在函数里对 a 做了一个本地拷贝,一下子就 Accepted 了。
好了,故事讲完了,学到了什么道理呢? :p 也许我就是被“过早优化”深深毒害的典型吧。其实我最早接触的编程语言是 Java ,那时候甚至根本不知道什么叫优化。后来接触到 C 和 C++ ,似乎为我以前写的那些(Java 的)程序“new 了以后不 delete”感到有些胆战心惊。各种各样的(关于 C 或 C++ )书里面总是会讲到各种各样的技巧用于优化,结果我就被毒害成现在这样了,对于一个比较费事的计算,我会马上就给他加上缓存:
int value()
{
if (m_value_invalid)
{
m_value = compute_value();
m_value_invalid = false;
}
return value;
}
可是即便如此,我也会觉得也许这个函数会很低效,是的,我总是会觉得每次都要执行一次 if 判断会花掉很多时间,我甚至都不敢轻易调用函数,就想把所有的东西写到一个函数里面,不行就加入宏函数,再不行就用 inline 函数,连 inline 也不能用,必须要调用函数的话,参数也得能用引用的用引用,能用指针的用指针……有一次写代码随手就打了一个 const int &v 这样的参数列表出来,自己都觉得似乎是中毒已深了。
其实关于过早优化的道理我也明白,嗯,我现在也在努力改善这个问题。先要写出一个正确的程序出来,而关于优化,无疑是通过 profiler 分析以后更有针对性地优化是最好的,否则只会事倍功半了。第一步写代码是要写得漂亮的,甚至可以用脚本语言来作原型。写得漂亮有两个好处:
- 代码漂亮,易于阅读,方便维护,毕竟代码大多数情况下都是需要人来阅读的,只是偶尔才拿去给编译器看看而已。
- 代码结构清晰显然是比代码乱七八糟的时候更不容易出现 Bug 。而且抽象过的代码通常比乱成一团的代码数量要少,有一个定理不是说代码行数和 Bug 数是成比例增长的吗?
Comments (3)
先写代码再优化,20%的代码占用了80%的运行时间,必要时再做优化。
编程中,经验也不是全都对未来有帮助的,有时是禁锢和束缚。