大头
Table_bottom

标签云
Table_bottom

分类
Table_bottom

日历
二月
28293031123
45678910
11121314151617
18192021222324
252627282912
Table_bottom

评论
Table_bottom

留言
Table_bottom

微博
Table_bottom

热门文章
Table_bottom

随机文章
Table_bottom

豆瓣上谁关注这里
Table_bottom

链接
Table_bottom

搜索栏
Table_bottom

RSS
RSS Link
Table_bottom

功能
Table_bottom

页面
Table_bottom

计数器
462885
Table_bottom

访客统计
Table_bottom

存档
Table_bottom

代码之美 - 081022

《漂亮的调试》,Andreas Zellerddd的一个bug为引,介绍了增量调试(Delta Debugging),主要思想类同二分,算法好理解,可是程序看不大明白。

程序如下。

  1. def dd(c_pass, c_fail, test):
  2.     """Return a triple (DELTA, C_PASS', C_FAIL') such that
  3.        - C_PASS subseteq C_PASS' subset C_FAIL' subseteq C_FAIL holds
  4.        - DELTA = C_FAIL' - C_PASS' is a minimal difference
  5.          between C_PASS' and C_FAIL' that is relevant with respect
  6.          to TEST."""
  7.  
  8.     n = 2 # Number of subsets
  9.  
  10.     while 1:
  11.         assert test(c_pass) == PASS # Invariant
  12.         assert test(c_fail) == FAIL # Invariant
  13.         assert n >= 2
  14.  
  15.         delta = listminus(c_fail, c_pass)
  16.  
  17.         if n > len(delta):
  18.             # No further minimizing
  19.             return (delta, c_pass, c_fail)
  20.  
  21.         deltas = split(delta, n)
  22.         assert len(deltas) == n
  23.  
  24.         offset = 0
  25.         j = 0
  26.         while j < n:
  27.             i = (j + offset) % n
  28.             next_c_pass = listunion(c_pass, deltas[i])
  29.             next_c_fail = listminus(c_fail, deltas[i])
  30.  
  31.             if test(next_c_fail) == FAIL and n == 2:
  32.                 c_fail = next_c_fail
  33.                 n = 2; offset = 0; break
  34.             elif test(next_c_fail) == PASS:
  35.                 c_pass = next_c_fail
  36.                 n = 2; offset = 0; break
  37.             elif test(next_c_pass) == FAIL:
  38.                 c_fail = next_c_pass
  39.                 n = 2; offset = 0; break
  40.             elif test(next_c_fail) == FAIL:
  41.                 c_fail = next_c_fail
  42.                 n = max(n - 1, 2); offset = i; break
  43.             elif test(next_c_pass) == PASS:
  44.                 c_pass = next_c_pass
  45.                 n = max(n - 1, 2); offset = i; break
  46.             else:
  47.                 j = j + 1
  48.  
  49.         if j >= n:
  50.             if n >= len(delta):
  51.                 return (delta, c_pass, c_fail)
  52.             else:
  53.                 n = min(len(delta), n * 2)
  54.  

1,第三行注释翻译成:“C_PASS是C_PASS'的子集,C_FAIL'是C_FAIL的子集”。想了一想,没错,函数是逐步缩小c_pass和c_fail之间的差异,在书中例子里,也是通常情况下,c_pass是空的,c_fail是“失败全集”。

2,在 j < n 这个循环里,n = 2, i = 0, 把全集分成两部分,如果第一个 if 成立,c_fail等于其中一部分,n = 2, offset = 0, break是否是跳出这一堆if-elif-else?跳出的话回到循环开始,j 没有机会改变,i 也就仍然等于0。我尝试着模拟几种情况,n等于2、4、8,似乎程序跑步到 else 里,j = j + 1 没有机会被执行,i 的值也就得不到改变。也许我对 test 函数的返回理解有误。摇头叹息看不懂看不懂。

作者说在这本书的O'Reilly网页上也有这段代码,于是去下载,下载的代码和书上的不大一样,算法是一致的,清楚多了,一看就明白。再回头看上面这一段,还是觉得不大对。作罢作罢。

文中还提到Continuout Testing。作者说他开了一门课,专门讲授科学方法和增量调试,课程幻灯片和参考文献在:http://www.whyprogramsfail.com/,可是我打不开这个网页。还有增量调试的主页:http://www.st.cs.uni-sb.de/dd/

代码之美 - 081017

《代码如散文》。Yukihiro Matsumoto自然对Ruby大夸特夸。作者用简洁的一篇散文谈了谈漂亮代码的几个因素,简洁,保守,简单,灵活。

有两句话应该时时记住:

程序中不应该包含无用的信息。

不要重复代码,不要把相同的东西编写两次。

代码之美 - 081016

《优雅代码随硬件发展的演化》,因为题目的诱人,选择读这一章,开了头就发现上当。

磕磕巴巴把前面的问题描述读完,被示例程序14-1难倒了。且不说MATLAB的奇怪写法,LU因式分解我也没搞清楚,于是,这个30多行的程序,来来回回多少遍也看不明白。自然也就不明白作者说的这个代码如何地漂亮。

了解了一下LU因式分解,再去看程序,还是头晕。于是决定放弃看代码,包括后面的FORTRAN代码和C代码。

马马虎虎看完这一章的汉字,一知半解的,大约知道Jack DongarraPiotr Luszczek(他的主页上links提供了很多好看链接)在说漂亮的代码如何高效地利用存储器层次结构获得高性能。

代码之美 - 081008

《Linux内核驱动模型:协作的好处》这章篇幅不大,可读得费劲。

上来就有两句话没看懂:在2.4版本的内核中,每一个设备的物理部分都由一段总线特定的代码来控制。总线代码负责各种不同类型的任务,而每一种具体总线的代码之间则没有交互。

后一句的原文是:This bus code was responsible for a wide range of different tasks, and each individual bus code had no interaction with any other bus code.

这里,总线特定代码(bus-specific code)是什么意思?

然后,Greg Kroah-Hartman提出两个问题,1是在解决电源管理问题时,内核需要知道不同设备的连接关系;2是不论哪一台USB打印机先启动,两台打印机的名字永不变。

其他系统的一般解决方法,1是内核中放一个处理设备名的小数据库,2是通过文件系统中可以直接访问设备的devfs类型来导出设备的所有信息。

对Linux来说,内核里放数据库是不能接受的,同时,Linux的devfs文件系统实现中“存在一些众所周知的且难以消除的竞争条件,导致几乎所有的Linux发布的版本中都不能依赖它。”这句话怎么理解?

再然后,作者用一个“简单”的例子展现了,展现了什么呢,我觉得是展现了C语言的复杂用法。如作者所说:是的,非常强大,只要你清楚地知道你正在做什么。

不信就看看这个宏吧: 

  1. #define container_of(ptr, type, member)    ({    \
  2.     const typeof( ((type *)0) ->member ) * _mptr = (ptr);    \
  3.     (type *)( (char *)_mptr - offsetof(type, member) );})

作者通过介绍Linux内核中解决前面提到的两个问题所需的数据结构和支持函数的演变,来说明协作给Linux带来的好处,还好文末有个总结,否则我又要忘了他要说什么。

代码之美 - 081007

《漂亮的测试》这一章很容易阅读,Alberto Savoia介绍如何写测试用例,漂亮的。

他举例说明如何写漂亮的测试代码,这个过程又是如何使被测代码变得更好。其实,更加强调的是程序员本来就应该测试自己的代码。

有多少程序员像画家一样,常常放下笔,站远点,从不同角度,在不同光线下,审视自己的作品呢?

我很少编写程序去测试自己写的函数,我的同事也一样。我们更多依赖运行整个程序检查结果是否正确,依赖测试组的同事们。

作者介绍的是Java程序员常用的JUnit

不要给自己找借口,只要想做,办法总是有的。

挑了几个错误,填写到这里

代码之美 - 081003

收到了《代码之美》,把目录翻来翻去,在33章里找我最容易能看懂的,似乎并没有哪一章让我觉得可以顺畅阅读不用多加以思索的。

最后挑选了第24章《美丽的并发》,作者是Simon Peyton Jones,他用Haskell语言来介绍STM(Software transactional memory),看得我很头大。注意力几乎全被Haskell语言占据了,3、5行的程序段却费了不少脑筋去思量。以至于文章最后作者在总结的时候,我都没有感觉到他说的所有的好处到底在哪里。回头想想,似乎是那么回事,可一到细节,脑子里搅和的还是语言的细节。

反正我记住了,最大的好处是使并发程序的模块性更好。还避免了不少常犯的错误。

这一章里的代码有下载

我还想知道,Haskell多用在什么地方?记录下Haskell的官方网站,那里可以找到很多信息,下载很多东西。

再记下这本书的英文版勘误信息