2011年5月8日

人生的追求

你成天忙这些为了什么?你的理想或长远追求是什么?

两个简单的问题可以直击你的心灵。

儿时的我,经常一个人跑到西南交通大学的校内书店瞎逛,记得买回的第一本书讲的是科学家的故事。打那时起,我的理想就是长大成为一名科学家。

今年4月,研究所改变了头衔体制,我从原来的Research Fellow变成了Scientist I。虽然本质上没有任何区别,但是我还是小小的激动了一把。因为儿时的梦想可以说在头衔上已经实现了。

前两天小组开会,老板又提到了让我们得有长远规划,例如未来3-5年想做什么。之前还有一次,老板对我说,我将来可以有两条长远规划,一是去一流公司纯做工程开发,二是纯做研究。

回想自己从2000年上大学以来的经历,工程开发远大于科学研究。总结自己做研究最快乐的时光,居然是五次数学建模竞赛、自己独立半年时间完成的科技创新项目、以及硕博期间组织的五次全校机器学习小组活动。

所谓经常做什么就会在什么方面学得多些。十年来参与过不少项目的申请、组织、实际完成以及结题后,我对于做项目的激情居然大于对做研究的感觉了。

为什么呢?这个感觉似乎不符合我的理想预期啊。仔细想想,应该和Sunner提到的"人的快乐来自于持续的成就感"不谋而合。

作项目过程中的那种不断涌现的成就感远比作研究过程中的成就感要多得多。或者这个感觉只是我的个人感受。我猜想那些论文生成器类型的研究人员应该在研究过程中也会有持续的成就感。

在网上查了一下什么是科学家。看完下面链接中的描述,才算更多了解了科学家的方方面面。儿时的梦想不清晰,不明确,不知道还有这么多的细节。为了理想而努力吧。

http://baike.baidu.com/view/66827.htm

细细总结自己十年来关注的事情,提炼成关键词不外乎就这么几点:数学、编程、英语、机器学习、太极、自然语言处理。仔细想想自己无数次给自己制定的计划和兴趣的不断转移,都不外乎在这几点里面。

2011年4月21日

羽毛球与太极云手

昨晚打羽毛球时又遇到了那位发球很快的同事。他的发球有的左有的右,有的吊短,有的拉长,最常用的就是反后方的快球。更难办的是当你往后退一点准备接反后方求时,他又来一个靠外侧的吊球。只要他发球我们就比较紧张。

一次,球过来时拍档更快的接过去了,而且回的是一个那位同事反后手的位置,得分了。

原来,接这位同事球的时候应该比他更快。轮到我接他球的时候,为了应对他的变化多端,我把球拍排面竖直往下,位于脸正对的前面一尺位置。球过来时,我可以快速的变换接球的姿势回球。

成功一次后,第二次失败了。原因是手不够灵活。第三次,我先采用这个姿势,按太极云手的方式左右转了几次,凭着云手的感觉,我接球的以静制动的成功率很快上升,到后来这位同事的球我都能回过去了,以至于他一看到接球的是我时,他都有点紧张了。

太极云手的感觉不错。忽然想到,球拍守中线并快速变换的策略和李小龙练的永春拳是一个思路。都是以静制动,以不变应万变。

2011年3月31日

Google Cpp Style Guide 1.1 #define保护:里面没写清楚对svn或者git管理项目源代码的假设

=============================
1.1. #define 保护
Tip 所有头文件都应该使用 #define 防止头文件被多重包含, 命名格式当是: <PROJECT>_<PATH>_<FILE>_H_
为保证唯一性, 头文件的命名应该依据所在项目源代码树的全路径. 例如, 项目 foo 中的头文件 foo/src/bar/baz.h 可按如下方式保护:
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
xxxxx

Google Cpp Style Guide 1.1 #define保护:里面没写清楚对svn或者git管理项目源代码的假设

------------------------------------------------------------
1.1. #define 保护
Tip 所有头文件都应该使用 #define 防止头文件被多重包含, 命名格式当是: <PROJECT>_<PATH>_<FILE>_H_
为保证唯一性, 头文件的命名应该依据所在项目源代码树的全路径. 例如, 项目 foo 中的头文件 foo/src/bar/baz.h 可按如下方式保护:
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
…

初步接触Google Style和Cpplint

试着看了一下Google Style的C++编码规范,先随手写了一个最简单的程序来试试Cpplit。代码如下
------------------------------------
#include <iostream>

using namespace std;

int main() {
    cout << "Hello World!" << endl;
    return 0;
}
------------------------------------
运行指令
------------------------------------
g++ main.cpp -o main
./main
------------------------------------
得到结果
------------------------------------
Hello World!

------------------------------------
运行Cpplint,得到的结果如下
------------------------------------
main.cpp:0:  No copyright message found.  You should have a line: "Copyright [year] <Copyright Owner>"  [legal/copyright] [5]
main.cpp:1:  Streams are highly discouraged.  [readability/streams] [3]
main.cpp:3:  Do not use namespace using-directives.  Use using-declarations instead.  [build/namespaces] [5]
Done processing main.cpp
Total errors found: 3
------------------------------------
第一条说我没有版权信息,第二条没看懂,第三条说的是不能用std全部空间,建议使用具体用到的函数。

仔细上网查了半天,终于弄懂了第二条是什么意思。

------------------------------------------
5.9. 流
Tip 只在记录日志时使用流.
定义: 流用来替代 printf() 和 scanf().
优点: 有了流, 在打印时不需要关心对象的类型. 不用担心格式化字符串与参数列表不匹配 (虽然在 gcc 中使用 printf 也不存在这个问题). 流的构造和析构函数会自动打开和关闭对应的文件.
缺点: 流使得 pread() 等功能函数很难执行. 如果不使用 printf 风格的格式化字符串, 某些格式化操作 (尤其是常用的格式字符串 %.*s) 用流处理性能是很低的. 流不支持字符串操作符重新排序 (%1s), 而这一点对于软件国际化很有用.
结论: 不要使用流, 除非是日志接口需要. 使用 printf 之类的代替.

使用流还有很多利弊, 但代码一致性胜过一切. 不要在代码中使用流.

拓展讨论:
对这一条规则存在一些争论, 这儿给出点深层次原因. 回想一下唯一性原则 (Only One Way): 我们希望在任何时候都只使用一种确定的 I/O 类型, 使代码在所有 I/O 处都保持一致. 因此, 我们不希望用户来决定是使用流还是 printf + read/write. 相反, 我们应该决定到底用哪一种方式. 把日志作为特例是因为日志是一个非常独特的应用, 还有一些是历史原因.

流的支持者们主张流是不二之选, 但观点并不是那么清晰有力. 他们指出的流的每个优势也都是其劣势. 流最大的优势是在输出时不需要关心打印对象的类型. 这是一个亮点. 同时, 也是一个不足: 你很容易用错类型, 而编译器不会报警. 使用流时容易造成的这类错误:
cout << this;   // Prints the address
cout << *this;  // Prints the contents
由于 << 被重载, 编译器不会报错. 就因为这一点我们反对使用操作符重载.

有人说 printf 的格式化丑陋不堪, 易读性差, 但流也好不到哪儿去. 看看下面两段代码吧, 实现相同的功能, 哪个更清晰?
cerr << "Error connecting to '" << foo->bar()->hostname.first
     << ":" << foo->bar()->hostname.second << ": " << strerror(errno);

fprintf(stderr, "Error connecting to '%s:%u: %s",
        foo->bar()->hostname.first, foo->bar()->hostname.second,
        strerror(errno));
你可能会说, “把流封装一下就会比较好了”, 这儿可以, 其他地方呢? 而且不要忘了, 我们的目标是使语言更紧凑, 而不是添加一些别人需要学习的新装备.

每一种方式都是各有利弊, “没有最好, 只有更适合”. 简单性原则告诫我们必须从中选择其一, 最后大多数决定采用 printf + read/write.
------------------------------------------

最终改好的程序如下,Cpplint能通过,g++也能通过
------------------------------------------
// Copyright 2011 Bill_Lang
#include <cstdio>
int main() {
    printf("Hello World!");
    return 0;
}
------------------------------------------

直接看Google Style会一会儿就烦了,但是配合着使用Cpplint,还是挺有乐趣的。看来还能帮助自己提高C++编程的实际水平。

推荐朋友们也玩玩这个。

2011年3月30日

2011年3月简述

对照年度总结

每周精读一篇论文:这个月项目压的太紧,居然一篇也没读!!
锻炼:打了三次羽毛球,还有一次是球馆在装修;参加了一次台球厅的活动,斯诺克不好打,但更有意思
读书:这月读书只完成一本书(《大学,究竟读什么》)的1/5。读完大学再看这本书,感觉挺有意思
工作:今天上午顺利完成计划内的项目发布,保持了三个月升级一次的记录,感谢折腾我的Bug们,两个完整的周末都搭进去了
生活:师弟正华实习结束回哈尔滨去了,新加坡的芒果和榴莲开始大面积上市了,好吃但不能多吃

下月主要改进:项目告一段落,开始读论文,读书,读代码,读PPT

2011年3月26日

鬼魅般的Bug吃掉了我的榴莲

一周来,不停的和各种Bug斡旋着,三日前解决了一个重大的GBK里GB2312外汉字的不能翻译的问题,算是小小进步。

三日来被一个鬼魅般的Bug萦绕着,这个Bug飘忽不定,在一个确定的配置下在确定的句子上翻译时就会Crash掉,原因据GDB说是内存重复释放。但换一个配置就会在另外的特定句子上Crash掉。挖地三尺,都快到六尺了还没有搞定。

昨晚太太买回两盒刚上市的新鲜榴莲犒劳我,吃完一盒打算另一盒放到冰箱。结果拎着垃圾袋和另一盒榴莲去楼道口仍的时候,竟然将垃圾袋和另一盒榴莲随手同时扔进了那种直接通往地下的垃圾通道。瞬间就意识到"问题的严重性"。太太听了后,过了一会儿才算谅解。

仔细想想,应该算是这个鬼魅般的Bug吃掉了我的榴莲。Bug还得继续调啊。送你榴莲了,让我Fix掉这个Bug吧~~