一点一点前进...

0%

假定有一个8x8的象棋棋盘,去掉对角上的两个小格,剩余62个格子。给你31个2x1的纸牌,你能完全覆盖整个象棋盘吗?如果能,给出一个解决方案;如果不能,给予证明。

这个题目在离散数学与组合数学这本书中有介绍。

首先抛出答案,不能。
为什么不能呢?
我们给棋盘染色,黑白相间,那么去掉的两个格子是同一个颜色的,不妨设去掉了两个白色的,也就是说,象棋盘上有32个黑色格子和30个白色格子。用2x1的条形纸牌去覆盖,不管你怎么放,都会盖住一个黑色的,一个白色的,也就是说,不管你怎么放,都无法覆盖32个黑色格子和30个白色格子。所以答案是不能。

原题链接
Peter有九个4个面的骰子,类似于金字塔的样子,每个面上标有数字,分别是1-4。
Colin有六个6个面的骰子,就是正常的骰子了,每个面上标有数字,分别是1-6。
现在他俩比赛,各投掷一次,点数之和比较大的胜。点数之和一样的话算作平局。
问题是,Peter胜利的概率是多少?要求答案是0.abcdefg这种形式。也就是小数点后面有七位数字。

看到题目的想法是,不要用double类型,可能会有精度误差,以至于最后的答案不正确。
那就只考虑分子好了,因为分母就是4的9次方,6的6次方,最后得到答案的前一步除一下就好。

首先计算Peter扔出的点数之和的概率分布。我使用一个字符串表示Peter掷出的结果,字符串长度为九,每一个字符只能是1-4这四个数字。下面是一段递归代码,得到了所有可能的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private static List<string> PeterResults = new List<string>();
private static void GenPeterResults(string num, int nth)
{
for (int i = 1; i <= 4; i++)
{
if (nth == 8)
{
PeterResults.Add(num + i);
}
else
{
GenPeterResults(num + i, nth + 1);
}
}
}

运气不错,数组的长度是4的9次方。看样子代码写对了。
接着构造一个数组,用于存放每种点数之和出现的次数。该次数除以4的9次方就是概率,但是正如前面所说的,我只考虑分子。

1
2
3
4
5
foreach (var s in PeterResults)
{
int[] digits = s.Select(c => int.Parse(c.ToString())).ToArray();
Peter[digits.Sum()]++;
}

下面计算Colin扔出的结果的概率分布。其实,上述算法肯定是有效的。不过,考虑Colin只有6个骰子,用int值表示,111111-666666也不过50万种组合,换个更暴力的算法。

1
2
3
4
5
6
7
8
for (int i = 111111; i <= 666666; i++)
{
int[] digits = i.ToString().Select(c => int.Parse(c.ToString())).ToArray();
if (digits.Where(digit => digit == 0 || digit > 6).Count() == 0)
{
Colin[digits.Sum()]++;
}
}

如果出现了数字0或者比6大的数字,那么是不符合题目要求的,扔掉即可。

好了两个概率分布都有了,开始比赛吧。如果Peter的点数比Colin大,计算下概率,最后加起来就好了。

1
2
3
4
5
6
7
8
9
10
11
long numerator = 0;
for (int p = 0; p < Peter.Length; p++)
{
for (int c = 0; c < Colin.Length; c++)
{
if (p > c)
{
numerator += Peter[p] * Colin[c];
}
}
}

其实p和c从1开始就可以了,但是不会对正确性和性能有什么影响,而且看起来更优美。
现在,分母是4的9次方乘以6的6次方。那么用分子除以分母,保留7位小数就是答案了。

1
return ((double)numerator / 262144 / 46656).ToString("F7");

虽说这本是是入门级的,虽说我做Web开发有段时间了,但是就和书的译序说的一样,基础不牢固。故而,买此书读之。

花了几周的零散时间了这本书,怎么评价呢?盛名之下,其实难副。或者是,图灵过度的吹嘘了这本书。

首先这是一本基础的面向零基础读者的一本书,图文并茂,介绍了相关的知识点和概念。这本书,也就如此了。

没有理论联系实践的东西,也没有深入分析的东西,读者读过一遍,了解了相关知识,不会再去读第二遍。

最后,不推荐买这本书,去图书馆看一看就足够了。

在京东6.18搞活动的时候,买了一本。
这是一本小说,很快就读完了。

书本身是白色的封皮,简约,大方。除了标题,作者这些必要的东西,什么也没有。书外面有个黑色的封皮,有一个奥斯卡小金人,各种推荐的信息,是啊,书商为了书卖得更好,搭上电影的快车,无可厚非。也是,如果不是因为电影很有名(声明下,我还没有看过这个电影,但听说拿了奥斯卡奖。),我也不会买这本书。

本书讲述了在伊朗时间之后,作者作为伪装部门负责人,成为营救小组的负责人,负责整个事件。不用说,最后,顺利的营救了六名逃出大使馆的美国人。

毋庸置疑,作者是一个有着艺术家气质的特工人员。没事的时候,或者思绪有问题的时候,一个人待在画室画画。
作者讲述了一个真实的故事,讲述了自己所经历的故事。身为中情局的特工,沉着,冷静,有担当,在绝境中找到希望,一步步,脚踏实地,做好充足的准备工作,最终不辱使命,营救了六个美国人,给了美国政府一个定心丸。

虽然都是特工,都是去完成某个任务,但是这本书描述的故事和我们看到的大片,比如impossible mission,007,Enemy of the State这种特工片,有很大的不同。没有激烈的场景描写,没有特别的高科技装备,更没有敏捷的身手以一当十。有的只有平平淡淡的叙述,在平淡中展示任务的困难,特工的细心,运筹帷幄。
相同点也是有的,比如随时会被敌人发现而招来杀身之祸;都围着国家或者某个集团的利益而奋斗;有为男主角而担忧的家人;等等。

总体说来,这本书值得一读。回头有空,把电影下载下来看看。

半个月前,我妹一个人来北京玩。来之前总觉得她一个人,不能独立坐火车,坐飞机,她能行吗?

来了之后发现,她能把自己照顾的很好。是啊,她已经是快16岁的大姑娘了。有了一定独立生活的能力了。

想想我15岁的时候,我一个人到乌鲁木齐读书,人生地不熟的,住校读书,要知道,这是我第一次离开了石河子市。其实,石河子地区很大,但是除了生活的149团,就去过石河子市。18岁的时候,又只身一人,坐着44小时的硬座,来到北京读书。第一次离开新疆,来到遥远的首都。那个时候,什么也不太懂,第一次到这么大的一个城市。不过,那个时候的我也过得还行,慢慢的成长起来。

回到我妹这里,已经不再是我记忆中的小孩子了。是啊,不知不觉,我来北京都八年了。她也从一个小学生,到了高一。时间过得多快啊。
听说在火车上和大家打成一片,同时还知道注意安全,挺好的。而且,通过带她去北大,去警院,去我公司,对她是有一定的教育意义的,给她打了一点鸡血。知道好好学习了,以后才能有个不错的地方学习生活。

再说说我,八年过去了,也都过了26的生日,谈婚论嫁都提上了日程。慢慢的,我要肩负起更多的责任,对家庭的责任,对妻子的责任。慢慢的,我也要组建一个自己的家庭,我,老婆,还有未来的孩子。更多的责任,需要我变得更强大,能够担当起做儿子的责任,担当起起做哥哥的责任,担当起做老公的责任,担当起做爸爸的责任。加油吧,路还很长,而且还充满着未知数,或许是荆棘,或许是鲜花,不管怎么样,都必须走下去,做一个有担当的人,足够了。

在端午那个三天假期,我就在警察学院读完了这本书,前前后后没有花太长的时间。今天才写点感悟,原因很简单,懒人一个。

毋庸置疑,对于一个二十多岁的年轻人来说,这本书题目太大,讨论的话题太深,如果没有类似的亲身经历,肯定不能够深层次的理解书的要义。不过,我对这本书的看法和对《老子》一书差不多,在人生的每个阶段读,都会有不一样的理解,有着不一样的收获,但有一个共同点,那就是引发我的思考,让我更好的生活。

作者,维克多·弗兰克尔的生活几乎覆盖了整个20世纪。他在三岁的时候,就喜欢思考人生和生命,长大了,自然学习了自己喜欢的东西,并以此为业。他经历了集中营的生活,继续思考人生和生命:不管是遇到怎样的困境,人类都有能力去选择如何面对苦难。
“苦难不一定是追寻意义所必要的,但尽管有困难,生命仍然可能有意义。”我们所要做的事情就是,就是在任何时候,任何情境下,都要努力选择自己的生活,活出生命的意义。当然,承担不必要的苦难,与其说是一种英雄行为,不如说是一种自虐。

面对各种挑战和机遇时,态度决定一切。积极的态度,可以使人感受到快乐和满足,同时,使人能够经历住磨难。相反,消极的态度,加剧苦难,削弱满足感和幸福感,甚至让人抑郁,得病。我们做出的选择,应该是积极的,而不应该是消极的。

作为治疗精神病的一种疗法,意义疗法,弗兰克尔用此处理一些精神疾病。但是对于我来说,生命的意义,不仅能让自己活下去,生活下去,更重要的是,能够活出生命的意义,活出生命的精彩。

这里是问题的原始链接

通过置换*3的第一位得到的9个数中,有六个是质数:13,23,43,53,73和83。

通过用同样的数字置换56**3的第三位和第四位,这个五位数是第一个能够得到七个质数的数字,得到的质数是:56003, 56113, 56333, 56443, 56663, 56773, 和 56993。因此其中最小的56003就是具有这个性质的最小的质数。

找出最小的质数,通过用同样的数字置换其中的一部分(不一定是相邻的部分),能够得到八个质数。

我折腾这道题很久很久,也没能得到解,于是乎,我Google了Prime digit replacements(这是英文标题),看了看别人的分析,找到了问题的关键点:如何选出可能是解的质数。下面也着重讲解这个。

首先说明一下,我直觉觉得这道题的解答是六位数,仅仅是直觉,因为做了很多欧拉项目的题目。其实,如果答案不是六位数,比如是五位数,分析方法是不变的。

变化几个数字呢?变化的第几位数呢?
肯定不能变化最后一位数。因为,质数的最后一位只可能是1,3,7,9,离八个质数还很远呢。

变化几个数字呢?
假设是1个,考虑下被三整除的性质。
假设除去变化的数字之外的五位数之和模三等于一:那么变化的这一位数不能是2,5,8。最多只能得到七个质数。
假设除去变化的数字之外的五位数之和模三等于二:那么变化的这一位数不能是1,4,7。同上。
所以不可能只变化一个数字。

假设是2个呢?按照上面的思路,可以得出结论,不可能只变化两个数字。

假设是3个呢?同一数字*3,模三等于0,不影响其余三位数字之和模三的结果,不会推出矛盾。
4个,5个?!也是不可能的。

至此,我们得到一个结论:六位数字,最后一位不能是变化的,同时,每次要变化三个数字。
那么,题目的结果一定要满足下面的模式:

1
string[] patterns = new string[] { "110001", "101001", "100101", "100011", "011001", "010101", "010011", "001011", "000111" };

其中,0表示变化的数字,也就是说,对于某个质数,这三位要一样;1表示不变化的数字。

现在,我们来生成可能的候选质数:

  1. 我们先生成所有的六位数质数:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    long[] primes = Utils.GenPrimes(100000, 1000000);

    //[begin, end)
    public static long[] GenPrimes(long begin, long end)
    {
    List<long> primes = new List<long>();
    for (long i = begin; i < end; i++)
    {
    if (Utils.IsPrime(i))
    {
    primes.Add(i);
    }
    }

    return primes.ToArray();
    }

结果有将近七万的质数。

  1. 把符合模式的数字筛选出来,我用了很笨的方法,但是数据量不大,无所谓了,速度还是很快:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    primes = primes.Where(l =>
    {
    for (int i = 0; i < patterns.Length; i++)
    {
    string pattern = patterns[i];
    List<char> chars = new List<char>();
    for (int j = 0; j < pattern.Length; j++)
    {
    if (pattern[j] == '0')
    {
    chars.Add(l.ToString()[j]);
    }
    }

    if (chars.Distinct().Count() == 1)
    {
    return true;
    }
    }

    return false;
    }).ToArray();

过滤完之后,只有不到4000个符合题目的质数了。

接下来,我使用了一套很笨的连通图的算法找到这八个质数,复杂度很高,但是基于4000个数,还是很快就能得出结果了。

当然,如果你也Google下Prime digit replacements的话,你会找到几个非常赞的解法。

昨天,在试着解决一道欧拉项目的问题,第六十九题

一开始,想法很简单,foreach循环1-1,000,000,计算每个值的phi(n),这样就能得到结果了。
一头扎进了这种想法,计算速度超级慢,就搜索各种互质数的性质,希望加快这一过程,最终,1s大概能处理1w数据,上10w之后需要2s,这还是很慢,根本不可能是正确的解决方案。

从两点半折腾到三点,还没结果。。。纠结。。。开会去了。

会中,继续思考这个问题,要使得n/phi(n)最大,phi(n)越小越好,互质数越少,那就要求n包含质数因数的个数越多越好,于是乎拿出手机,从2开始,一个质数一个质数的往上做乘法,计算到510510,下一个质数是19,乘完之后积就大于一百万了。

开完会后,输入510510,正确了!
换个脑子,手算就得到了答案真开心。

是的,当你想问题想不明白的时候,或者是陷入了某个泥潭,不妨站起来走一走,或者换件事情做,这样做的目的是让自己换个脑子,啊哈,或许,问题迎刃而解。

昨天的事情让我想到当时面试百度,三面,面试官出了一个题目:
有一堆元器件,比如说1000个,它们能够检测其他元器件是好的或者是坏的。如果自身是好的,那么就能真实的检测出被检测元器件的好坏,反之,不能检测出来,也就是说,检测的结果是随机的,和被检测的元器件好坏无关。有一个前提,这里一半以上都是好的。想出一种解决方案,罗列这1000个元器件是好是坏。

当时就在想如何拿一个去检测其他,然后再分析,让面试官给了一点提示,还是没想出来方法。当然,最后还是拿到了offer。
这里想说的是,当我走出了百度大厦,前往西二旗地铁站的路上,又开始想这个问题,一下子,想到了解决方案。

让999个元器件去测试一个,因为一半以上都是好的,那么,最后统计这999个结果,就能确定该电子元器件的好坏。如果这个是坏的,继续这种方式;如果这个是好的,那么用这个好的去测试其余的,就能得到正确结果了。

很多时候,问题的解决方法很简单,但是由于某种原因,我们会陷入泥潭,或者走了错误的道路而不知道回头。这个时候,暂停一下,让自己换个脑子,再去想这个问题,答案就在眼前。

历时好几个周末的时间,于上周末把这本书读完了。现在把自序复制过来,中间穿插自己的一点想法,作为读完此书的总结。
接下来,把上次买的《活出生命的意义》看完,给自己来点鸡汤,思考下人生。

伯特兰·罗素在他的自传中回忆了他青少年时期的一场危机:
有一条小路,穿过田野,通向新南盖特,我经常独自一人去那里观看日落,想象着自杀。然而,我最终没有自杀,因为我希望了解更多的数学知识。
Leo:确实,数学有他自身的美,数千年来,吸引着无数人。
诚然,只有极少数人能够如此虔诚地皈依数学,然而有许多人能够领会数学的力量,特别是领会数学之美。本书谨献给那些希望更深入地探索漫长而辉煌的数学史的人们。
Leo:大多数人都是普通人,但是,他们往往也能体会到数学带来的美感。
对于文学、音乐和美术等各种学科,人们的传统做法是以考证杰作——“伟大的小说”、“伟大的交响乐”、“伟大的绘画”——作为最恰当和最有启发性的研究对象。人们就这些主题著书立说,授课讲学,使我们能够了解这些学科中颇具创新意识的里程碑和创造这些里程碑的伟人。
本书采用类似的方法来研究数学,只不过书中大师们创造的不是小说或交响乐,而是定理。因此,本书不是一本典型的数学教材,没有一步一步地推导某个数学分支的发展。本书也不强调数学在确定行星运行轨道、理解计算机世界或者结算支票等方面的应用。当然,数学在这些应用领域极其成功。然而,并不是这些世俗功利促使欧几里得、阿基米德或乔治·康托尔为数学殚精竭虑,终生不悔。他们觉得没有必要借功利目的为自己的工作辩解,正如莎士比亚不必解释他为何要写十四行诗而没有写食谱,或者凡高为何要画油画而没有画广告画一样。
Leo:正是这些伟大的天才,给我们留下了这么多宝贵的东西,让我们这些普通人去体会数学之美。
Leo:正是因为这本书不是教材,不用拘泥于很多限制,使用了很生动有趣的方式一步一步的推进,做到了如此引人入胜的程度。
在本书中,我将从数学史的角度来探究一小部分最重要的证明和最精巧的逻辑推理,并重点阐述这些定理为什么意义深远,以及数学家们是如何彻底地解决了这些迫切的逻辑问题的。本书的每一章都包含三个基本组成部分。
第一部分是历史背景。本书中的“伟大定理”跨越了2300多年的人类历史。在讨论某个定理之前,我都将先介绍历史背景,介绍当时的数学状况乃至整个世界的总体状况。像其他任何事物一样,数学也是在一定的历史环境中产生的。因此,指明卡尔达诺三次方程的解法出现在哥白尼日心说公布后两年和英格兰国王亨利八世死前两年是有意义的,强调青年学者艾萨克·牛顿1661年进入剑桥大学学习时,王政复辟对剑桥大学的影响也是有意义的。
Leo:这部分说了很多故事,要是再添加一些名人轶事就更好了。
第二部分是人物传记。数学是有血有肉的实实在在的人的造物,而数学家的生平则可能给人以灵感、示人以悲剧或令人惊呼怪诞。本书所涉及的定理体现了许多数学家的勤奋努力,从交游广阔的莱昂哈德·欧拉到生性好斗的约翰·伯努利,以及最世俗的文艺复兴时期的人物杰罗拉莫·卡尔达诺,不一而足。了解这些数学家的不同经历,有助于我们更好地理解他们的工作成果。
第三部分,即本书的重点,是在这些“数学杰作”中所表现出的创造性。不读名著,无从理解;不观名画,无从体味。同样,如果不去认真地、一步一步地钻研这些证明方法,也不可能真正掌握这些伟大的数学定理。而要理解这些定理,就必须全神贯注,加倍努力。本书各章仅仅为理解这些定理梳理线索。
Leo:其实,按理说,我的数学储备应该可以推理出本书的这些定理,但是由于个人原因,数论、集合中有些东西,只是草草的看了个大概,木有深入研究,惭愧。
Leo:这本书的连贯性很好,每章后有个后记,大致会从本章的重点人物的时间点讲到下一个主要人物出现前。
这些数学的里程碑还具有一种永世不灭的恒久性。在其他学科,今天流行的时尚,往往明天就被人遗忘。一百多年前,沃尔特·司各特爵士还是当时英国文学界中最受尊重的作家之一,而今天,人们对他已淡忘。20世纪,超级明星们匆匆来去,转瞬即成历史,而那些旨在改变世界的观念,最终却常常变成思想垃圾。
的确,数学的口味时常也会改变。但是,严格遵循逻辑的限定条件而得到完美证明的数学定理则是永恒的。公元前300年欧几里得对毕达哥拉斯定理的证明,丝毫未因时光的流逝而丧失它的美与活力。相比之下,古希腊时期的天文学理论或医术却早已变成陈旧而有点可笑的原始科学了。19世纪的数学家赫尔曼·汉克尔说得好:
就大多数学科而言,一代人摧毁的正是另一代人所建造的,而他们所建立的也必将为另一代人所破坏。只有数学不同,每一代人都是在旧的建筑物上加进新的一层。
从这一点来看,当我们探讨伟大数学家历久弥新的成果时,就能够逐渐体会奥利弗·亥维赛精辟的论说:“逻辑能够很有耐性,因为它是永恒的。”
Leo:这个计算机软件这个领域差不多,新技术层出不穷,但是本质的东西是不变的,是根基,是值得人们慢慢体会,反复体会的。
在选择最能体现数学精髓的这些定理时,我考虑了许多方面的因素。如前所述,我首要考虑的是找到具有深刻见解或独创性的论题。当然,这里有一个个人好恶的问题,我承认,不同的作者肯定会选取不同的定理。除此之外,能够直接看到数学家通过巧妙的演绎,将看似深奥的问题变得清晰易懂,确实是一种不同寻常的经历。据说,聪明人能够战胜困难,而天才则能够战胜不可能。显而易见,本书将呈现许多天才。这里有真正的经典——数学界的《蒙娜丽莎》或《哈姆雷特》。
Leo:个人觉得,作者选的挺好的,大多数普通人都是数学界的白痴,而作者是数学家,眼界、深度都比我们强多了,这也决定了他能选出更好的(概率上是这样的)。
当然,选择这些定理也有其他方面的考虑。首先,我希望本书能够包含历史上主要数学家的定理。例如,欧几里得、阿基米德、牛顿和欧拉必不可少。忽略这些数学人物,犹如研究美术史而不提伦勃朗或塞尚的作品一样。
Leo:NB的人太多,以至于高斯这样的人物只能出现在欧拉章节的后记部分。
其次,为求丰富多彩,我兼顾了数学的各个分支。书中的命题来自平面几何、代数、数论、分析学和集合论等各个领域。各种分支,以及它们之间的偶然联系和相互影响,为本书增添了一些新鲜的气息。
Leo:这个想法很好,作者指出很多类似于代数和几何的关联这种小的亮点。
我还希望能在本书中展示重要的数学定理,而不仅仅是一些小巧的智力题。实际上,本书的大部分定理或者解决了长期存在的数学问题,或者提出了意义深远的问题留待未来解决,或者二者兼而有之。每一章的结尾处都有后记,一般都会论证一个由该伟大定理提出的问题,同时会介绍其在数学史上的影响。
现在再跟大家说一说难度深浅的问题。显然,数学有许多伟大的里程碑,其深度和难度只有专家可以理解,而所有其他人都会感到莫测高深。在一本针对一般读者的书中引入这些定理是十分愚蠢的。只要具备高中代数和几何知识即可理解本书所论述的定理。但有两处例外,一是第9章在讨论欧拉的工作成果时应用了三角学中的正弦曲线,二是第7章在讨论牛顿的工作成果时应用了初等微积分。许多读者可能已经掌握了这些知识,而对于那些尚未掌握这些知识的读者,本书做了一些解释,以帮助他们克服阅读中的困难。
Leo:这是一本科普书,出现了很多很深的定理,但是作者都是在历史背景、传记或者后记里面讲一讲,主定理还是浅显易懂的,至少我是能够完全理解。
必须强调,本书不是一本学术著作。一些重大的数学问题或微妙的历史问题当然不可能在这种书中一一述及。虽然我尽力避免编入一些错误的或历史上不准确的材料,但这里也不是对所有问题的所有方面刨根问底的时间和场合。毕竟,本书是一本大众读物,不是科学著作或新闻报道。
就此,我必须对定理证明的真实性说几句。在准备写这本书的时候,我发现,为了让现代读者能够理解这些数学资料,我不得不对定理创始人最初使用的符号、术语和逻辑战略做一些变通。完全照搬原作会使一些定理非常难于理解,但严重偏离原作又与我的历史目标相冲突。总之,我尽力保留了定理原作的全部要旨和大量细节。我所作的修改并不严重,在我看来,不过就像是用现代乐器演奏莫扎特的乐曲一样。
因此,我们即将开始两千年的数学里程之旅。这些定理虽然古老,但在历经许多个世纪之后,却依旧保持着一种新鲜感,依旧能展现古人的精湛技艺。我希望读者能够理解这些证明,并能够领会这些定理的伟大之处。对于达到这一境界的读者,我希望他们不仅会对他人的伟大之处肃然起敬,还会因为能够理解大师著作而增加成就感。
Leo:伟大的数学之旅结束了,想动脑的可以读一读,想看故事的可以读一读,想增加对数学兴趣的朋友更要读一读了。

本片文章为转载,主要参考原文外刊的译文,Leo的话为我的理解、心得。
问答网站stackoverflow.com的一个主要功能体现就是:软件开发人员无需再从书本上学习编程,就像Joel所说的

程序员看起来都不再读书。市场上编程方面书籍的数量和编程从业人数相比来少的可怜。

2004年在《The Shlemiel Way of Software)》一书中Joel也表达了相同的观点:

大部分的人都不读点什么或写点什么。大部分的程序员都不读软件开发方面的书籍,他们不去软件开发方面的网站,他们不去Slashdot参与讨论。

既然现在的程序员都不读书,他们如何学习编程?他们用最原始的方式:捋起袖子就写代码——同时开启第二个窗口来从互联网收集经验和知识。互联网是一部百科全书。获取知识信息更快,更高效,从网上获取编程知识明显是一种更聪明的方法。Doug McCune在Why I Don’t Read Books这篇文章里贴切的写出了他的感受,我相信他描述的这种心情是相当普遍的。
我认为技术图书出版业应该为此承担主要责任:

  1. 大部分编程书籍都写得很烂。 写书出版的门槛,就我个人发现,已经基本上不存在了。图书出版业虽然很热闹,但这并不能说明它能提供比你在广袤的互联网上找到的更好的内容。虽然每年都有成百上千的编程图书上市,但也许可能只有2、3本是值得你花时间去读的。
    Leo:好书本就不多,往往一些烂的译者又能毁掉部分好书,对于中国程序员而言,好书就更少了。
  2. 编程书论斤买,而不是论知识量。 我们会有这样一种感觉,编程书籍的厚度跟它的内容质量似乎成反比。书的部头越大,里面所承载的有用信息越少。那些动辄上千页的参考书究竟有什么用?你真的会用它来查找吗?拿着都费力。
    Leo:但是我还是会拿书来查找,好的书籍能有更多的解释,但是不如看网上的帮助文档方便。
  3. 都是面向新手的速成编程书籍。 我丝毫没有反对新人进入编程领域的意思。但我从来都是认为“24小时[某种编程语言]速成教程”这类书对我们的这种职业是有害的。这种书都灌输着一种短视的思想,求快,求最简单的省事的做事方法,这导致初学者误入歧途——或就像我喜欢提到的,“PHP”。玩笑!玩笑!
  4. 编程书籍色情化。 有些人认为把一大摞厚厚的,看起来很重要的编程书放在案头——基本上没看过——会映衬出是一个水平很高的程序员。正如David Poole曾经有一次在邮件中跟我说的,“这种事情我是绝对不会做的”,说的正是这些编程书籍色情化的现象。这也是我经过思考决定拒绝购买Knuth写的Art of Computer Programming一书的原因。我们应该去买有实践价值的书,你真正会去读的书,更重要的,你能拿来实用的书。
    Leo:买书固然重要,看书更重要!

作为一名书作者,我很惭愧。我和别人也合写了一本编程书,而且我并不认为你应该买它。我不是在说反话。我想说的就是字面上的意思。但不管怎样,那并不是一本很糟糕的书。我对我的书合作者怀有最大的敬意。但你能从网上找到比这本书更丰富的信息。抱着一本死书不放是最不可取、最浪费生命的事。
互联网无疑正加速编程书籍的死亡,但有一些证据显示,甚至早在互联网诞生之前,很少有程序员遍读大量编程书籍。我很吃惊的在《代码大全2》一书中看到了这样的段落:

你可以炫耀一下了,因为你在读这本书。你已经学到了比软件产业里大部分人都要多的知识,因为大部分的程序员一年都不会读一本书 (DeMarco and Lister 1999)。每天读一点,坚持不懈,你就能成为专业高手。如果你能每两个月读一本好的编程书,大概一周35页,你很快就能对业内的知识有坚实的掌握,能很快让你从周围所有的人中脱颖而成。

Leo:很庆幸,我制订了一个读书计划,当然,重在坚持!
我相信早在《代码大全》1993年第一版时里面就有这样的原话,但我们无法证实,因为没有那一版的书。经过这网上的搜索,发现了Steve McConnell在《人件》中引用的段落:

关于读书情况的统计数字让人非常的泄气:比如,大部分的软件开发人员手头上都没有一本关于他们的工作方面的书籍,更不用说读过一本。 这事实让人对这个领域里的工程质量感到担忧。而对于我们这些写书的人,那更是悲剧。

我很痛心的读到reddit上的这些评论,看到人们把stackoverflow.com网站的宗旨使命理解为对编程书籍的否定。怀着一种对当前编程书籍市场复杂的心情,我要说,我喜欢编程书! 我这个编程博客就起始于一篇推荐程序员必读书籍的文章开始的。很多我的文章都是在讲述我对于一些经典编程书籍里的核心思想浅显的理解。
如何让这看似矛盾的语句能够调和,如何能统一这矛盾的爱与恨?你看到了没有,处处都有编程书籍,处处都是编程书籍。
Leo:在任何时候,书籍都很重要!
优秀的编程书是没有时间限制的。它们会超越语言的限制,IDE的限制和平台的限制。它们不是解释how,而是why 。如果你不得不五年就清扫一下你的书架,那请相信我,你买错了编程书
Leo:越是优秀的编程书籍,历久弥香,不会过时,不会下架!
我的编程书柜是任何东西都换不去的。我无时不刻都在使用它他们。事实上,我写这篇文章时就翻阅了它们数次。
my-programming-bookshelf
我不想再复述我的这些推荐的读物,因为这些年我一直在拿它们炫耀。

(更新:Tim Spalding以我的名义建立了一个LibraryThing,很多人把上面照片里面的书录入了进来。真酷!)

可我必须要号召的是:我最喜爱的五本最重要的编程书,你们每个正在从事编程工作的程序员都应该有拥有——并且要 这些读物,极富实用价值,年复一年,不论我做什么样的编程工作,它们从未贬值。它们值得一读再读,每次我有了更多年的经验,回来重新阅读它们,都会让我对软件工程获得更深更明锐的认识,如果你还没有拥有这些书,那你在等待什么?
代码大全2
点石成金
人件
程序员修炼之道
Facts and Fallacies
Leo:最后一本貌似没有译本,其他都是有的。我只买了其中一本,貌似只看了一点,其余的都在亚马逊收藏夹里面。哎,惭愧啊。
我的主张,让stackoverflow.com这样的网站成为这里永恒经典编程书籍的有益补充。没有任何途径,东西,形式能替代这些书籍。
另一方面,如果你不幸是《Perl语言傻瓜书》的作者,那你要留意你的背后,因为我们很明确就是在针对你。
Leo:按照作者的观点,这类书是没有必要买的,但是我个人感觉,对于零基础的学习者来讲,快速看一下,能入门,也还可以。