《代码英雄传》

曾经在网上看到过一个都市武侠的故事,篇幅不长,但很有趣,讲述了一群身怀绝技的普通人在现代都市中的生活。之后我就把这个故事忘了,直到很久以后突然想起,我问自己:如果我们生活在一个武侠世界,我们的生活可能会是什么样的?于是便有了《代码英雄传》这个故事。

故事不长,两万字左右,一般阅读速度约一小时能读完。内容纯属虚构,不过也有一些现实中的影子,比如故事中的三大诸侯分别以现实中的BAT三巨头为原型(当然,仅仅是原型,没有黑哪家的企图 ^_^)。

这是一个普通的武侠故事,当然,如果你了解一些编程,同时还对目前国内主要互联网公司有一定了解,或许会从中发现更多的笑(槽)点。

最后,地址如下:

1、简书地址

2、GitHub地址

3、PDF版下载地址

希望你喜欢这个故事,也欢迎吐槽指正。:)

涂鸦之老婆大人

2014 12 25 00 40 02

2014年基本上一整年都在加班,很多原本想做的事都没有做,博客也几近荒废了,临近岁末,回首这一年,却似乎没有特别值得记下的东西。如果说今年有什么要特别感谢的,那就是老婆大人,在我加班的时候,默默地打理好家里大大小小的事,在背后给予我坚实的支持。

2014年,准备说再见!

查IP归属地的Chrome插件

日常学习和工作中,我经常需要查询某个IP地址的归属地,每次都打开查询网站比较费事,于是便做了一个Chrome插件,你可以使用Chrome浏览器访问这儿安装。使用很简单,如下面图片所示:

Search by right click

可以在页面上选中一个IP,然后在右键菜单中选择查询,也可以点击浏览器插件栏图标,在弹出菜单中查询。

Search by popup window

IP来源自第三方,目前使用了IP138QQ IPIP.cn的服务,将来可能会有所调整。

插件的代码是开源的,见https://github.com/oldj/SearchIP。欢迎fork一起完善。

《Web性能实践日志》

参与翻译的新书《Web性能实践日志》上市了,如标题所言,这是一本关于Web性能的书,求支持、求传播。:)

Web performance daybook volume 2

以下是我写的译者序,也可以看作是对本书的简介:

对Web开发而言,性能是永远也绕不过去的话题,你正在阅读的,就是一本关注Web性能的书。

与市面上其他关于性能的书不同,本书并不是一个人或一个团队写的,而由多位活跃在业界最前线的顶级专家的文章集结而成,可谓是一部Web性能领域的百家之言。

这些专家中有一些已经是名声在外了,比如Nicholas Zakas、Steve Souders等,有一些对国内的读者来说可能还比较陌生,但无论你是否听说过他们,我相信你都能从他们的文章中有所收获。

作为一本关注前沿的书,本书的视野并不仅仅局限于HTML、JavaScript、CSS及图片等常规的前端性能优化主题,还讨论了网络环境甚至协议对性能的影响。同时,在移动互联网越来越热的今天,本书也探讨了若干移动端的性能问题及优化方案。如果你正准备在Web性能领域探索一番,本书或许能帮助你扩宽视野。

本书适合有一定经验的读者。如果你正关注Web性能问题,那么本书就是为你而写的。限于篇幅,书中对各个问题通常只介绍关键点而很少深入细节,但在读过这数十位专家的文章后,当你遇到类似的问题时,或许你能从这些专家的经验中找到进一步探索的方向及勇气。

涂鸦之南方巨兽龙

南方巨兽龙

南方巨兽龙是已知的最巨大的陆地肉食性恐龙之一,体长15.5-17米,体重8.35-10.52吨,生活于9千3百万至8千9百万年前上白垩纪土仑阶。

涂鸦时画恐龙的好处是,除非你的读者对古生物有很深入的研究,不然很难发现你画中的问题。比恐龙更好画的是未来时代的星际战舰,因为古生物学家毕竟还是存在的,但未来战舰学家目前似乎还没有出现。:)

恐龙是让人着迷的物种,在大部分人的印象中,恐龙都是庞然大物,不过实际上恐龙的种类非常多,有一些体型很小巧,比如美颌龙,据称和现在的鸡差不多大。

关于恐龙的科幻小说我喜欢的是刘慈欣的《白垩纪往事》,作者设想了这样一种可能:如果思考能力与动手能力分别位于两个不同的物种,文明会如何发展。

IE中使用location.href跳转丢失referrer的问题

曾整理过一个各种页面跳转方法中referrer丢失的情况,其中提到,在IE中,使用类似 location.href = "a.html"这样的方式跳转页面时,在目标页面中 document.referrer的值会是空。这应该是IE的一个 bug。

大多数情况下,这个问题不会给我们带来麻烦,但有时候我们不得不用JavaScript来跳转,同时又要在下一个页面收集 document.refer,这时就得想想其他办法了。

Form GET方法

首先想到的是使用Form表单,用JS发起一个GET请求。代码类似下面这样:

这个方法可以如同预期地工作,目标页面中 document.referrer能正常指向上一个页面。

A元素模拟点击方法

网上搜索了一下,发现司徒正美的博客上记录了这个问题的另一个处理方法

原理很简单,先创建了一个 A元素,指定其 href属性为目标链接,然后再使用JS触发它的点击事件。经测试,在目标页面也能正常取到 document.referrer

这个方法的原始出处在这里:http://webbugtrack.blogspot.com/2008/11/bug-421-ie-fails-to-pass-http-referer.html

这个方法代码更简短一点,应该比上面的使用 form表单的方案更好一些。

关于2014的最大算式

除夕晚上,我们在某个来往的扎堆群里出了一道关于2014的趣味数学题,题目是这样的:

请使用2、0、1、4四个数字加上运算符,构造一个算式,使其计算结果尽可能大。数字的顺序可以随意调换,可以使用括号,但不能使用阶乘等单目运算。

题目很简单,比如 2 + 0 + 1 + 4 就是一个可能的解答。不过,这个算式的结果显然太小了。

另外还有一个要注意的是,我们要使用常用的或大家公认的运算符,不能使用偏门的或自定义运算符,不然的话就会有问题。

比如,如果我定义一个运算符“#”,让 a#b 的结果是一个巨大的数字,这样显然可以得到很大的结果,但别人也可以定义更大的运算符,这样的比较恐怕永远不会有结果出来。

同时,我们把阶乘运算(n!)也禁止了,因为这种单目运算可以重复使用,比如:

4210!!!!!!!…

当然,我们可以禁用连阶乘,不过简单起见,我们直接把整个阶乘都禁用了。

传统解

扎堆里很快有人给出了答案:

2^(4^10)

这儿的 ^ 表示乘方运算。

如果只能使用加、减、乘、除、乘方、开方等传统运算符,这大概是能得到的最大算式了,它相当于 2^1048576,如果把结果写出来,会是一个长达 31 万位的数字。

使用位运算后的解

不过,既然扎堆中基本都是程序员,大家自然把位运算也用上了。位运算对程序员来说也是一种常见的公认的运算。

位运算中,我们加了一个假设:左移运算(<<)时可以不考虑溢出。在一些编程语言(比如Python)中,的确有这样的特性,只要内存足够,左移永远不会溢出。

如果加上了位运算,注意到左移一位相当于乘以 2,于是我们有了更大的算式:

1<<(2<<40)

这个算式相当于 2^2199023255551 ,一个大得惊人的数字。

更多

除了上面的解答,还有不少同学给出了各种有趣的解法。比如:

421/0

这个算式中直接将 0 作为除数,得到的结果可以认为是无穷大,某种程度上说可以秒杀所有其他回答。不过让一个数除以 0 还是比较怪异,这种方案最终被否决了。

另外还有一些方案用到了位运算中的取反操作,比如:

2^(40^~1)

根据CPU的不同,~1 得到的结果也不同,但总之会是一个很大的数字。不过,这种方案的值取决于硬件,多少有一些遗憾。

除了取反外,也有同学使用无符号右移来得到一个大数,比如:

4^((0-1)>>>2)

这个方案也很有创意,但结果同样也取决于硬件。

小结

最终我们认为的最佳方案是:

1<<(2<<40)

你有没有更好的方案呢?

当你被人拒绝的时候

我不记得这个观点是在哪儿看来的了,原话也不记得了,大致意思是当你被人拒绝时,你应该感到高兴,因为这说明你触及了你的世界的界限。

1

上图显示的是你现在的世界,这个世界上,有些事情是你不能做的,有些则是你可以做的,在你可以做的事情里,有些则是你已经在做的。

如果你总是在做自己可以做的事,那么你永远也不会被人拒绝,当你被人说“不”时,你一定正试图做一些你不能做的事,如下图。

2

有可能,这些事你的确不能做或不应该做,那么没关系,你至少知道界限在哪里,至少知道在这个方向上你可以做的事有哪些。

但是,也有可能,这些界限并不是无法改变的,或许你通过努力,能把这个界限往前推进一点点。

3

好了,现在你可以做的事情变多了,那些原来的禁忌之处你已经可以自由来往了。

于是,你的世界变成了这样。

4

在线生成热图的JavaScript库:heatmap.js

heatmap.js源自前段时间为KISSY写的一个组件,用途为在网页上生成热图,当然,现在它是独立的,不依赖于任何第三方库。

它的使用非常简单,首先要有一个Canvas元素,比如:

然后,就可以创建HeatMap对象了,比如:

一个示例图形如:

Snip20131029 36

另外,这个JS库的算法来自我以前写的另一个基于Python的热图库:pyHeatMap

关于乱停车的概率题

听闻我厂新厂区发生了若干次乱停车的问题,某些同学占了别人的车位,导致车位的主人无法正常停车。在这儿,我们抛开孰是孰非的评论,仅从数学的角度来考察一下这个问题,如果一位同学随便停车,可能会影响到多少人呢?

问题

为了方便讨论,让我们把问题重新定义一下:

设厂区有 n 个车位,对应的也有 n 位开车的同学,每位同学有一个专属的车位,车位与同学之间是一一对应的关系。假设最先到的 1 名同学没有遵守停车规则,他没有刻意去寻找自己的车位,而是随机选了一个位置停车(注意,这儿说的是随机,也就是这位同学也有一定的概率将车停到自己的位置上),后来的同学如果发现自己的车位没有被占,则将车停在自己的车位上,如果发现自己的车位被占了,则也在剩下的车位里随机选择一个停放。我们的问题是,从期望上来说,最后会有多少人停错位置?

分析

为了便于分析,我们假设前 q 名同学(1⩽q⩽n)都不遵守规则,选择随机停车。很容易可以看到,前 q 名随机停车的同学,正好停到自己的位置上的概率为 1/n,则他们停错的概率为 1- 1/n,即 (n-1)/n 。

我们用 F(i) 来表示第 i 名同学停错的概率,则有:

F1

从第 q+1 名同学开始,他们会优先停在自己的车位上,仅当自己的车位被占时才随机停车,所以他们停错位置的概率即是他们的位置被前面的车占了的概率。可以发现,第 q+1 名同学的车位被占的概率(车位被前 q 名随机停车的同学占的概率)为 q/n ,这也是他自己停错位置的概率。即:

F2

继续分析,可知第 i 名同学停错车的概率(他的车位被前 i-1 名同学占了的概率)为:他的车位被第 1 名同学占了的概率 + 他的车位被第 2 名同学占了的概率 + … + 他的车位被第 i-1 名同学占了的概率。

因此,考察第 q+2 名同学,他的车位被前 q 名同学占了的概率为 q/n,即我们只需要求出他的车位被第 q+1 名同学占了的概率即可。而第 q+1 名同学要占他的车位,说明第 q+1 名同学的车位也被前面的同学占了,他只能在剩下的车位同随机停放。于是,我们可以得到下面的算式:

F3

其中 G(i) 的含义是:在第 i-2 名同学发现自己的车位被占的情况下,第 i-1 个车位仍然空着的概率。因为只有这种情况下,第 i-1 个位置才有可能被 第 i-2 名同学占用。(n-i+2) 表示当第 i 位第 i-1 位同学准备停车但还没有停时剩下的空位置数量。

接着,我们又可以推出 F(q+3):

F4

观察上式右边,可以注意到它的前面的几项正好等于 F(q+2),即:

F6

接着,我们可以推出 F(i) 的通用公式,这是一个分段函数:

F7

好吧,看起来有点复杂,而且函数 G(i) 还没有展开。不过幸运的是,如果我们只考虑 q=1 的情况,我们马上能发现 G(i) 总是等于 1,因为只有一名同学随机停车,当他占了别人的车位时,就换成那名车位被占的同学开始随机停车,无论如何,当某位同学发现自己的车位被别人占了时,还没来的同学的车位一定都还是空的,没有被其他人占用。

这样一来,我们的公式就变成了:

F8

其中 i>2 的情况可以继续化简:

F9

再注意到当 i=2 时,上式正好等于 1/n,即:

F10

这样,我们便得到了当第 1 位同学随机停车时,各位同学停错车位的概率,或者说停错车位的期望值。接着,我们将这 n 位同学停错车位的期望值加起来,就得到了总的期望,设为 S(n) ,则有:

F11

这个函数如果画出一个图形来,是这个样子的:

F12

其中 n 的值为 1、2、3… 这样的自然数,这也是函数图像上出现“锯齿”的原因。

结论

从上面的公式及图形上,我们很容易计算出在不同的总车位下(即 n 不同时),第一名同学乱停车会导致多少人停错位置的期望值。

我们来看一个具体一点的数字,比如 n=100,计算可知 S(100) 约为 5.18。也就是说:

如果厂区某个区域有 100 个车位及对应的同学,第 1 位同学随机停车,接下来的同学如果自己的车位没被占就停自己的车位,被占了就在剩下的位置中随机选一个停车,如果这样的试验重复多次,那么平均下来每次约有 5.18 名同学会停错车位(包括第 1 位随机停车的同学)。

更多

网上有一些类似问题的讨论,比如搜索“傻子坐飞机问题”,即可找到一个类似的问题,不过那个问题更关注的是最后一名同学仍然能坐对自己的位置的概率,而不需要知道中间的同学坐对或坐错的概率。另外,《编程之美》一书中有一个“金刚坐飞机问题”也与本题非常类似。

上面 S(x) 的函数图像可以用一个对数函数的图像来拟合,误差非常小,如下图:

F13

其中那条红线的方程是:f(x) = 1.0534 * ln(x) + 0.3557 。