炉石传说如何偷看对面的手牌

炉石传说是一款暴雪最新出的卡牌游戏。这里我们简单对它的协议和客户端机制做一下分析。

炉石传说的客户端是采用的Unity3D+C#制作的。画面精良,美术细腻,可以说达到了 Unity3D 引擎作品中相当高的水准。3D的卡牌效果让人惊叹,暴雪出品确实必属精品啊。(Diablo III 除外)

EX1_062_premium由于采用的是Unity3D,可以预见移植到手机和Pad上毫不费力。因为采用的是C#,可以说缺点也是很显然的。C#的反编译非常的简单(虽然C/C++的反编译也难不到哪里去),大大降低了逆向工程(Reverse Engineering)的成本。这里不得不吐槽一下暴雪对微软系列的热爱,Web Server也统统用的IIS+ASP.NET,不出意外Game Server后端也用的是Windows Server以及SQL Server。可能也与暴雪一直专心于制作Windows Game有关。

下面我们不对客户端内容做任何反编译和分析,仅仅从通讯协议层来简单看看炉石传说的客户端在游戏时都做了什么。

我们先在本地用 tcpdump 监听一下 3724和1119端口,通过看包得内容,可以判断炉石传说的游戏 TCP 链接用的是 Protobuf 协议。Protobuf 协议的标志就是开头以 08 或者 0A 开始。

16:03:32.228771 IP 192.168.1.XX.53668 > XXX.XXX.XXX.XX.battlenet: Flags [P.], seq 229:256, ack 11411, win 8192, options [nop,nop,TS val 1131484283 ecr 57022610], length 27
0x0000: 5866 baf3 8757 040c cede b078 0800 4500 Xf...W.....x..E.
0x0010: 004f 6ddf 4000 4006 be15 c0a8 0158 7271 .Om.@.@......Xrq
0x0020: da42 d1a4 0e8c 4ab6 e5de 32f4 32b5 8018 .B....J...2.2...
0x0030: 2000 f655 0000 0101 080a 4371 147b 0366 ...U......Cq.{.f
0x0040: 1892 0200 0000 1300 0000 0811 1004 1800 ................
0x0050: 20ff ffff ffff ffff ffff 0128 00 ...........(.

Protobuf 是 Google 开源的一个公开协议。然而并不是说知道用 Protobuf 就能理解传得是什么内容。Protobuf 需要有详细的 .proto 参数配置文件定义传输的细节,否则对于其它第三方来说就是一团乱码。

通过一些逆向工程,我们大概知道了这个 .proto 参数配置是怎样的。炉石传说可以说是一个瘦客户端。客户端做的计算分析工作很少。这一点很符合暴雪的特点,比如魔兽世界也是这样的一个瘦客户端,大量的3D碰撞检测计算都放在了服务器端。

炉石传说把所有的客户端需要显示的细节,都通过服务器传来数据,其中甚至包含了客户端动画展示时需要的停顿。炉石传说的服务器端维护了一个 id=1~67,并且可以动态增加的字典,其中 1 代表系统,2 和 3 代表两边的玩家,4~35 是 id=2 玩家的所有牌的编号,而 36~67 是 id=3 玩家的所有牌的编号。系统、玩家、牌,这些共用一个属性表,这大大降低了定义的复杂度。

下面是一些通讯的简单例子:

初始化:
player{ ... 玩家属性初始化 ... }
init{ id:4 name:"HERO_03" attr{HEALTH=30} attr{PUT=1} attr{OWNER=1}
init{ id:5 name:"CS2_083b" attr{COST=2} attr{PUT=1} attr{OWNER=1} attr{CASTBY=4}}
init{ id:6 name:"" attr{PUT=2} attr{OWNER=1}}
........
init{ id:35 name:"" attr{PUT=2} attr{OWNER=1}}
init{ id:36 name:"HERO_08" attr{HEALTH=30} attr{PUT=1} attr{OWNER=2}
init{ id:37 name:"CS2_034" attr{COST=2} attr{PUT=1} attr{OWNER=2} attr{CASTBY=36}}
init{ id:38 name:"" attr{PUT=2} attr{OWNER=2}}
........
init{ id:67 name:"" attr{PUT=2} attr{OWNER=2}}

从这个初始化例子我们可以很清晰的看到,服务器给每个客户端初始化了 67 张“牌”,其中 1,2,3 是系统和两边玩家,4,5是玩家A的英雄卡 HERO_03 和英雄技能 CS2_083b,被放到了战场(PUT=1),6-35是玩家A的牌库,被放到了待抽牌堆(PUT=2),相应的,对面36,37是玩家B的英雄卡 HERO_08 和英雄技能 CS2_034,38-67则是玩家B的牌。

接下来的通讯协议分析就不一一说了,总之就是服务器向客户端通过设置这些牌的属性, 让客户端达到显示牌以及动画效果的目的。

那么有人要说笔者标题党了。技术细节看了一大堆,但是如何能看到对面的牌呢?难道服务器会直接在通讯协议里告诉玩家A,玩家B手里的所有牌么?

其实不然。暴雪在技术细节上做的还是很好的。只有在玩家把牌放入战场,对方才能通过通讯协议知道牌的内容。但是其中有一个小问题,就是:

每一次比赛牌的 id 并不会随机化洗牌!

就是说,玩家A和玩家B如果两次用同一副自己组的牌对打,玩家B如果给玩家A出示过某个 id 对应什么牌的话,那么下一次比赛玩家A就会知道玩家B还在手里的牌是什么!

说通俗一点的话,就是对圣斗士来说,每一招只能用一次,第二次用同样的招数就变得很不安全!

下面是一个和同一个好友同一副牌玩第 2 把的例子:

EX1_561_premium敌方 操作 开始
第 1 回合
玩家 铁喙猫头鹰 牌库 -> 手牌
玩家 刺骨 牌库 -> 手牌
玩家 任务达人 牌库 -> 手牌
玩家 刀扇 牌库 -> 手牌
玩家 幸运币 未知 -> 手牌 施法:
敌方 寒冰护体 牌库 -> 手牌
敌方 变形术 牌库 -> 手牌
敌方 魔爆术 牌库 -> 手牌

在第一回合,我们就清楚的知道了对方先手拿得三张牌是什么!

当然,在平时天梯和竞技场里,这个问题可能不会存在,因为每次遇到的选手都是系统随机分配的,都是第一次遇到。如果是打职业线上比赛的话,就难保不会有人通过这个办法作弊咯。

当然,目前游戏还在内测阶段,相信暴雪技术团队应该会在公测前修复这个问题吧。

除此之外,目前的通讯协议上还有下面几个 BUG:

  1. 对面手牌中的”奥秘牌“会在奥秘出示之前就通过通讯协议让另一方知晓。
    就是说虽然客户端没有提示,但是实际上对面一拿到奥秘牌,你的客户端就可以知道对面的哪一张是奥秘牌,虽然不知道具体是什么奥秘。
  2. 服务器错误的把每一方思考时候的选择数目发给了另一方客户端。
    选择数是你每一步有多少种可能。这是服务器端提前算好告诉客户端,然后让客户端提示用户做选择的。比如在1费回合你没有2费牌,只能点”结束回合“,这时候的选择数就是1个。通过判断对方每回合结束的选择数,你可以大致估计对方手牌里的费的多少,以及是不是法术指向牌。
  3. 虽然是第一次遇到某玩家,但是还是可能通过牌的 id 猜到对方某些手牌的内容。
    注意,因为没有通过随机化洗牌(shuffle),所以牌的 id 实际上是玩家从牌库中选择的顺序。有些玩家喜欢从1费开始选牌,有些喜欢从高费开始,但是一般两张同样的牌都会一起选进去,所以他们拥有相邻的id。比如你看见对方出了一张id=16的炎爆术,手里还有一张id=15的未知牌,那么你就知道下回合多半又是一张炎爆打脸了。

好了,简单写了这些,其实并没有太严重到逆天的 BUG,炉石传说还是一款好游戏。希望暴雪团队继续努力,早点出移动客户端,让笔者可以早点躺着玩。

 

浅谈如何修改游戏 (1)

很多很多年前,那时 DOS 游戏界有着两大逆天神器 GameBuster 和 FPE。不管是仙剑奇侠传还是红警神马的,一旦祭出神器,那是神挡杀神佛挡杀佛,弹指间敌人灰飞烟灭。

到如今几十年的发展,游戏变得越来越网游化和移动化。大游戏动辄十几G的容量,数据都存在服务器,外挂检查严而又严。小游戏在iPhone和Android上,麻雀虽小五脏俱全,对作弊的检查也是非常严格,数据加密和校验方法层出不穷。

然而道高一尺魔高一丈,本文就尝试粗浅的介绍下现如今修改游戏可以做的一些手段。

对于 Windows 游戏修改手段来说,大概可以分为下面一些层次,按照安全性排序:

  • 对数据段的内存读
  • 通过 PostMessage 对游戏模拟键盘和鼠标操作
  • 对 D3D9 的 EndScene 或者 D3D11 的 Present 函数挂钩子,进行远程调用
  • 创建远程线程 (RemoteThread) 去调用执行函数
  • 模拟游戏发送网络底层的命令包
  • 对数据段的内存写
  • 对代码段的直接修改

对游戏的数据段的读取,是最安全最可靠的。游戏本身无法判断其它应用是否对它进行内存读的操作。然而,只靠内存读可以做的事情非常少,不过依然有可能读取到游戏里隐藏给玩家的数据。比如人物的三维坐标、朝向、行进速度、或者隐藏Buff啦,比如法术的实际释放坐标和半径,以及前进路线啦。

想要更进一步的对游戏本身进行操作,那么可以用按键精灵,或者类似的工具,模拟鼠标和键盘事件发送给游戏。但是这依然无法产生逆天的效果,实际上可以做一些机械性重复性特别高的事情。这类工具本身的可侦测性也是非常低的,比较的安全可靠。

EndScene 和 Present 实际上是游戏UI线程一般在绘制完一帧图像之后必须调用的。很多录像软件也是 Hook 的这两个函数。所以实际上这是很安全而且很合法的钩子。在 EndScene 里做操作的好处在于,很多游戏里的操作函数需要运行在游戏UI线程。如果用 RemoteThread 的方式去调用函数往往会导致线程问题然后游戏崩溃。

RemoteThread 调用实际上用于一些简单的判断函数,比如得到某个游戏对象的名称,判断某个 NPC 的敌对状态。这些执行函数不需要在主线程执行,可以用 RemoteThread 飞快的调用完成。RemoteThread 的执行速度和 EndScene Hook 相比往往要快上百倍。

而发送游戏的网络底层命令包,则需要对游戏的网络通讯协议有一定的了解。它可以跳过游戏上层逻辑对命令合法性的判断,直接用底层协议对服务器通讯。通过这个办法可能可以做一些客户端里无法完成,但是服务器却允许的操作。它的安全性也不够高,如果命令非法,也可能造成服务器拒绝继续服务,导致掉线或者客户端崩溃的结果。

对数据段的内存写,实际上是早期游戏修改的大招了。然而,现今绝大多数网络游戏都有防护措施,他们不依赖客户端数据,服务器发现客户端数据不一致,就会拒绝继续服务,导致掉线甚至封号,得不偿失。所以这种手段用到的越来越少了。

对代码段的直接修改,是跳过一些客户端条件检查判断的手段。比如跳过客户端关于法术的 Cooldown 检查,直接向服务器发送法术发送命令。这个办法比直接发送网络底层命令包简单很多,只要对上层游戏逻辑进行修改就可以了,但是它却非常不安全。现今的网络游戏往往具有自我修改的检测能力,比如暴雪的 Warden 会定期的扫描自己可执行文件的代码段,看看有没有被注入钩子或者一些跳过检查的代码。如果被发现了你的客户端在内存中被做了修改,那么就等着过几天静悄悄的被无法登录游戏吧!

想要精确的定位到函数以及变量在内存中的地址,以及数据结构,就需要一些额外的辅助工具了。这里向大家介绍两个工具:Ollydbg 和 IDA Pro。可以说,有这两个工具在手,没有不能修改的游戏。IDA Pro 是非常强大的静态反编译工具,它的插件工具也相当多。读入静态 exe,它可以比较完美的分析出函数地址、函数调用关系、数据结构等。Ollydbg 是动态的运行中反编译工具,通过它,可以对在执行过程中的游戏增加断点,单步调试,等等。这两者可以结合在一起使用。

想要熟练掌握这两个工具,你必须会一些 X86 的汇编指令,可以熟练的编写汇编代码,对 C/C++ 编译有一些了解。有了这些基础之后,就可以随心所欲的对游戏下刀了。当然,有些游戏会有反跟踪和反“反编译”手段,想要修改成功,往往还需要一些耐心和毅力,以及一些直觉和洞察力。

最后,让我们来看看破解过得游戏能做到什么地步。其实很简单,就是能做到游戏的服务器端所容忍的上限。比如游戏客户端允许你的走路速度是 7 码/秒,施法距离是 40 码,而服务器考虑到网络延迟以及客户端的计算误差,往往上限会高一些,比如是 10 码/秒和 43 码。在绕过客户端限制之下,往往可以达到服务器允许的上限。再比如客户端在短期内连续发送很多移动命令,外加计算恰当的时间戳,可以让服务器觉得客户端是出现了卡顿,因此服务器会允许一大串移动命令和一大串偏移时间戳,在服务器看来,客户端卡顿了 10 秒并且移动了 70 码,但是客户端实际只经过了很短时间,做到了瞬间移动。这样的例子需要探索性实验。

如果服务器做的足够精美足够巧妙,其实是可以杜绝任何客户端的修改。然而这需要大量的服务器运算和负载。对于海量游戏数据处理来说,这无疑是会继续增加服务器运营费用和成本。因此很多国产网游的服务器检查非常粗糙和简陋,酝酿出大量的客户端修改和外挂。而好游戏在服务器端的强制检查判断则非常的严格和精妙,从而减少了客户端修改带来的收益。

最后告诫大家,游戏修改破坏平衡性,同时损害了游戏乐趣。网络游戏修改更加破坏了运营商的利益,破坏了游戏的生态环境,要小心被跨省追捕哦。修改有风险,入行需谨慎啊!

下次我们来谈谈 iPhone/Android 修改的一般性方法。

 

着凉与发烧

在中国传统里,冷是非常可怕的东西。比如传统坐月子时妇女一定要穿得严严实实,门窗紧闭不能出门。比如传统家长带孩子时,即使夏天也要捂的严严实实,袜子也是必不可少的,因为“寒气脚上来”。传统认为,感冒是着凉引起的。一旦着凉了,会变得怕冷。如果出现了高烧,需要用被子捂出汗来才能好。总之,冷是一切邪恶的根源。

众所周知,现代医学已经证明了,感冒是由感冒病毒引起的。它和寒冷到底有没有关系呢?其实医学界对此问题一直非常的感兴趣,做了很多得类似实验。比如,让两组大学生志愿者先接触感冒病毒,然后A组被迫去洗冷水澡,然后光着身子用空调对着头猛吹,B组则穿着大衣温暖舒适的在屋里休息。经过统计分析,两组人之后染上感冒的概率基本是一样的。类似很多实验都证明了这一点,就是感染感冒和冷热变化无关,只和是否接触到感冒病毒有关。

为什么直观感受觉得冬天感冒的人比较多呢?其实也有很多猜测,比如因为冬天大家减少了室外活动,在室内,因为近距离接触,感冒病毒增加了传播几率。

冷确实会带来一些不适。比如有些人遇到冷会流鼻涕,有些人会拉肚子。但这些并不是感冒引起的。人体在冷热变化很大的情况下会有各种不适反应,但是其实和感冒无关。其实在多接触冷热变化之后,人体也会慢慢适应冷环境,身体会变得更好。

7d000298gw1e09gaai20yj在西伯利亚生活的孩子们,两三岁就会脱光了在冰天雪地里跑步锻炼身体。毛主席也有冬泳的好习惯。冷锻炼实际上会增加抵抗力,改变人怕寒的习惯。一直窝在温暖房间里的孩子,才会一旦遇到冷就身体各种不舒服。

之前有网上流传过的一个帖子,说苏联当年让中国人养成了穿秋裤的习惯,就是为了要改变中国人种,让中国人从此不能耐寒。这篇文章毫无科学依据,也很搞笑,是一篇钓鱼贴。但是实际上有一些道理,就是人需要从小培养不怕冷的习惯,只有习惯了冷热变化,才不会变的娇生惯养,遇到冷就哭爹喊娘。

下面说说发烧。发烧大多数情况是由于感冒引起的。先来说一说人为什么会发烧。人是一种恒温动物。对于身体现在需要散热还是保温,是靠什么来调节的呢?人的脑部有一个视丘下部的区域,负责收集皮肤和血液里的温度变化,它的敏感度能精确到0.007摄氏度的程度。一旦发现冷了,就会收缩血管皮肤,减少体表流动血液,控制肌肉抖动制造热量;一旦发现热了,就会控制皮肤和血管扩张汗腺流汗,等待空气流动使汗液蒸发带走多余热量。在人生病的时候,视丘下部会适当调高这个温度,使得人体温度上升。为什么会主动调高温度呢?很多研究表明,这其实是进化出来的一种技巧,过热的温度会加速免疫反应,增强白细胞和巨噬细胞的能力,还会对某些对温度敏感的入侵细菌有致命作用。所以发烧其实是人体保护自己的一种手段。

在低烧的时候,其实不需要进行任何处理,因为上面说了,发烧本身是一种人体自我保护的机制,等病好了,人体又会自动恢复回原来的体温。但是如果高烧过了40度,就会对身体的细胞组织造成伤害,也可能让人体丧失温度控制的技能,这时候才需要对人体进行降温。这时候其实最为有效的,就是物理降温。

每当我看到有家长说孩子高烧40多度,物理降温无效,我往往会觉得很荒谬。自从空调被人类发明出来以后,物理降温早就不可能是什么问题了。有些家长一边给孩子吃着退烧药,一边用被子捂着汗。缺少空气流动,流再多的汗也无法散去身体里多余的热量,反而会使得孩子越来越热。发烧时确实会觉得冷,因为这时候身体温度阈值过高,大脑会调用体表血液去内脏,保证关键部位的温度,这时候会手脚冰凉,打哆嗦让肌肉抖动产生额外热量。但是发烧时如果要物理降温,千万不能捂着,不管如何吃药出汗,捂在被子里只会物理升温。

至于说空调会给高烧的孩子带来什么危害,实际上上面也说过了,寒冷不会给人体带来什么额外的烦恼,也不会增加孩子发病的几率,最多是有一些不适和不舒服。寒冷和人体的抵抗力无关。一旦发烧需要物理降温时,空调或者电风扇是最好的降温手段,衣服应该尽可能的少穿。有一个极端的例子,一位家长带着高烧的孩子去国外医院看病,大夫把孩子身上裹着厚厚的大棉袄剥光,拉过来一个电风扇,对着猛吹了10分钟,这时候高烧已退。

当然,水分的补充是必不可少的,因为人体主要带走热量的手段就是靠汗液的蒸发。吃退烧药,实际上是最后的不得已的手段,对于孩子来说,不管哪种退烧药都有强烈副作用,而退烧药的唯一作用也就是恢复温度调节,让人体增加汗液蒸发。退烧药并不会吃下去就能退烧,热量最终依然还是得依靠汗液蒸发被带走。

一个在水木社区上看到的真实的故事:孩子高烧了几天,不停的说觉得手脚冷。家长用大被子裹着孩子,给孩子喂了很多退烧药都没法退烧,孩子到后来还不肯吃药。家长把孩子带去北京306医院急诊。医院给用了有巨大副作用的中药注射液:喜炎平,刚开始吊水5分钟,孩子就陷入了过敏性昏迷。医院经过了半小时抢救总算是缓了过来。在医院住院了5天,吊了很多瓶水,最后康复。

这样的故事在身边不断上演,实际上,脱了衣服吹一吹电风扇或者空调就可以解决的事情,却演变为吃药、吊水、住医院。很多医生也一再在微博上呼吁,孩子感冒发烧不用送医院来急诊排长队,浪费钱浪费医院资源,也损害孩子的健康。儿童医院的急诊已经被发烧完全占领,真正的大病急病没法得到及时医治,医院往往为了让家长安心,不得不找一些无效甚至有害的药来吊水,最后是谋财害命的悲剧。

当然,不是说所有发烧都不提倡去医院。只有确认是感冒引起的发烧,是无需去医院的。因为感冒没有治愈手段,等待人体6-7天自愈即可。对于孩子来说,尽可能避免在6岁前吃任何药(除了打疫苗)是对他健康成长最大的帮助。

 

双缝实验的奥秘

今天让我们来聊聊一个绝大多数人在物理课上都做过的实验——双缝实验(Double-Slit Experiment)。

d833c895d143ad4b17c5559882025aafa50f06fa这个实验的最初发明者是英国科学家托马斯杨。在200多年前的1801年,托马斯杨第一次进行了这个非常简单又能揭露光的波动性的小实验,并写进了《自然哲学与机械学讲义》书里。可悲的是,当时同时代的科学家并不认可。光的粒子论当时盛行于世,杨的书籍20年无人问津,杨把自己反驳光粒子论的论文汇成小册子自己发售,据说只卖出了1本。

现如今,双缝实验已经跻身于物理学史上最经典的五个实验之列。2002年《Physics World》杂志对全世界物理学家做了一个调查评出了“十大最美实验”,其中双缝实验位居榜首。连当年的托马斯杨都没有想到,在200年之后,人类对双缝实验的研究越发热情高涨。费恩曼说,双缝实验包含了量子论的所有秘密和神奇之处。这个简单又无比深奥的实验,是至今物理学需要攻克的难题之一,对这个实验讨论和思考的越多,就越能对世界本质产生比哲学家更严肃的思考。

人类物理学的进步,其实和出生婴儿观察世界的过程一样,都经过了 观察->思考->修正->再观察->再思考->再修正 这样的循环。而反常识的发现往往就是推动物理学大发展的源动力。一旦观察到无法通过修正解决的现象,只有跳出框架,构造更大的框架来解释新的反常识现象。

在双缝实验之前,让我们先看看几个科学史上最著名的反常识的例子。亚里士多德认为,所有物体必须推动,才能前进。这是远古人们对自然很朴素的观察和认知。这个常识深入人心长达几千年,直到伽利略的横空出世。

伽利略和所有人一样,生活在有阻力的世界里,然而他却通过大脑想象出了无阻力的世界会怎样。伽利略石破天惊的提出了,物体如果在无阻力的环境下,会匀速直线运动,而且永远这么动下去!而物体受到力推动之后,反而会加速运动。日常生活中因为阻力广泛存在,才会造成物体有推力才会动的假象。

image002伽利略思考的方式也很有意思。在日常生活广泛存在阻力的环境中,是如何想象无阻力的世界是怎样的呢?伽利略想象了一个斜坡,假如一个物体从斜坡上滚下去,斜坡的高度保持不变,物体一定会随着斜坡上的阻力变小,以及斜坡的长度变大,越滚越远。如果斜坡的高度保持不变,斜坡的长度却被拉伸到无限,阻力变成零,那么物体是不是就可以永远这么动下去了?通过这样的创造性的跳出框架的思考,伽利略成功打破了人类几千年的常识,完成了一次物理学伟大的进步!

说到反常识,那么不得不提的还是光速的不变性。在伽利略时代之后,人们普遍接受了相对速度的简单朴素的概念。一个人A以10米每秒的速度往东跑,另一个人B以10米每秒的速度往西跑,那么A看到B就是B在以20米每秒往西跑。然而1884年,阿尔伯特·迈克尔逊和爱德华·莫雷为测量地球和以太的相对速度,进行了著名的迈克尔逊-莫雷实验,震惊了世界。这个实验发现,如果一个人A以10公里每秒的速度往东跑,另一个人B以30公里每秒的速度(也就是光速)往西跑,那么A看到B,发现B相对A还是30公里每秒的速度(光速)。就是说,不管你往什么方向,用什么速度,沿着光、逆着光,顺着倒着跑,那束光在你的眼里测量出来依然还是光速那么多,不多也不少。

u=4089854620,2149260910&fm=11&gp=0非常具有讽刺意味的是,迈克尔逊-莫雷实验的初衷是为了证明以太存在,以及光速可以和其它速度叠加,比如一倍光速加一个相对速度可以超过光速。然而实验目标全都失败了。这个实验又是那么好重复,导致当时所有物理学家一筹莫展,很多人觉得经典物理学就此坍塌。

速度等于长度除以时间,在速度恒定的情况下,是不是长度和时间发生了变化?反常识使大家跳出了原本框架,爱因斯坦在此时横空出世,通过把光速不变做为固定前提,证明了当物体在运动时,长度、时间这几个变量其实都发生了改变,导致光在他眼里依然还是光速。因此完美的解决了为什么光速永远是恒定的疑问。

当然,虽然物理上解决了光速恒定的问题,但是为什么我们这个世界会存在如此奇怪的一个不变量?为什么光速是所有物体运动的上限?为什么各种定律中会穿插着光速这个常量?这就是哲学需要考虑的问题了。在现代物理学中,光速常量C已经贯穿时空变换,成为各个方程式和运算中不可或缺的一个基本常量了。以至于最近人们(国际单位制)已经把一米直接定义成了光在真空中跑1/299,792,458的距离,将光速彻底锁死在了不依赖任何测量精度限制的 299,792,458 m/s。甚至于在很多物理学分支中,为了便于计算,现在直接把光速定义为1(C=1)。

下面让我们回到更加有冲击力的双缝实验。这个实验给人们带来的震撼,更超过迈克尔逊-莫雷实验证明光速恒定给大家带来的冲击感。

Single_and_double_slit_4这个实验最初是托马斯杨为了要证明光同样具有波的干涉衍射现象而发明的。实验也很简单,一根蜡烛(点光源),通过带有两条细缝的屏障(比如一张纸),在屏障后的墙上成像,会发现光在墙上形成了一道深一道浅的光栅,很像两个石子投入池塘,形成的两道水波浪在叠加打到岸边的样子。如果遮住其中一条缝,那么光就会经过小缝然后散开,形成衍射现象,均匀的照在墙上,形成均匀的光带。

这个实验可以通过波粒二象性比较好的解释。光有时候表现出波的特点,有时候则是粒子。在双缝实验中,光的粒子和其它光的粒子在空中发生了衍射效应,有的地方变亮,有的地方变暗,最后形成了最后屏幕上的波纹。

随后发现不光是光子,电子、质子、原子、甚至是比较大个头的分子段,都可以重复这个实验,产生干涉现象。所以只要是微观粒子,都可以重复双缝实验。

206px-Double-slit_experiment_results_Tanamura_2随着技术发展和进步,到近代,人们已经可以通过实验设备,控制每次只发出单个的一个粒子。2008年意大利实验室第一次用单个电子和真正的双缝完成了双缝实验。每次谨慎的从发射源只发射出一个电子,这个电子通过双缝中的一条缝,然后落在感光屏上。开始看上去似乎毫无规律,随着时间推移电子在目标感光屏上依然形成了光栅的模样。而遮住其中一条缝,光栅现象就会消失。还有很多类似的实验也重复了这个过程。

单个光子/电子是如何形成干涉条纹的?单个光子在通过其中一条缝的时候,可以知道另一边的缝的存在?或者是更诡异的,光子是同时通过了两条缝然后形成的干涉条纹?

这些问题,在随后一大堆实验中都进行了常识性的理解。有人猜测,只要加上观测器,知道每次光子经过的是左边缝还是右边缝,那么干涉现象就会消失,因为只有光子同时经过两条缝,才能形成干涉条纹。如果光子被发现经过了其中某一条缝,那么干涉条纹就会消失。这就是量子论中的观测会引起波函数坍塌的一种解释。

最开始的几个实验似乎能证明这一点。只要加上了观测器,看到光子每一次是通过左边还是右边的缝,那么干涉现象似乎就完全消失了。然而最近的一些实验却做出了相反结果,人们可以知道光子是通过左边还是右边缝,但是干涉现象依然存在,但是只是会非常大的减弱。2012年,研究人员做出了可以完美检测光子通过哪条缝,但是却对干涉条纹丝毫没影响的实验结果,可惜这个结果还有争议。因为测不准原理,在不影响光子的前进路线的前提下,同时还要检测光子的存在非常的麻烦,所以观测光子在哪条缝是否会影响干涉条纹,目前还有很大争议。(现在网上还有很多材料认为观测会造成影响,实际上是引用的老材料)

光子肯定是经过其中一条缝然后到达感光屏的。那么它在经过其中一条缝的时候,是不是知道另一边还有一条缝,这时候关上或者打开另一边的缝,对结果会有影响么?于是“惠勒延迟选择实验”就被设计了出来。

u=639416768,2938890662&fm=23&gp=0这个实验是双缝实验的变种,它将两条小缝拉长为两条管道,在管道的终点有一个设备可以控制,是将缝打开还是关上。(实际上并不是这么简单,这里只是类比双缝实验做了简单化描述)这个实验最早在1984年完成了第一次,随后在2007年完成的版本结果最为纯净。根据可重复的实验结果,已知一个光子进入一条缝之后,在光子快要到目的地时,忽然打开或者关上另一边的缝,居然会影响光子是不是产生干涉!

实验人员总结说,这个结果打破了因果论,因为可以在光子实际决定是不是产生干涉之后(在进入两条缝的管道的时候)很久,通过关闭或打开另一条缝来对光子的过去的选择造成了影响,并且这个关闭或打开的动作的信息传播速度也可能超越了光速,在关闭或打开缝之后,离缝很遥远的孤零零的光子就收到了讯息,知道在出缝之后自己是不是需要产生干涉条纹!

这个实验同样也引发了很多衍生实验,比如中科大在最近做的一个实验中,对控制缝是不是打开引入了量子化,即50%概率打开,50%概率关闭。由于量子纠缠,观测到的结果居然不是打开和关闭的简单叠加,而是一个很奇怪的中间态图案。通过修改概率,可以展现出慢慢从毫无衍射,到完全衍射的各种中间态。

爱因斯坦当年曾表示不信任量子论,说过一句很著名的话“上帝不掷骰子”,同时他相信存在一些隐藏变量并没有人发现,所以被迫用波函数和坍塌来描述量子行为。在此几十年,科学界被量子论一统,大家普遍认为爱因斯坦错了。然而,在双缝实验引发的各种奇怪诡异的现象被发现之后,爱因斯坦的隐藏变量又被人重新提起。很多人开始尝试跳出框架来对实验进行解释,但是往往都加入了隐藏变量的说法。究竟真相如何,恐怕还要等待更多的实验结果和理论猜想。

20071025161031378米兰·昆德拉曾说,人类一思考,上帝就发笑。即使是那些最严谨最严肃的思考,可能也只是为一个值得敬畏的、巨大的未知,提供些调剂品而已。物理学也是,随着劈波斩浪、打破常识,过去的物理学家已经跳出了很多很多个框架和约束,然而随着观测水平的提高,却发现还有更多的框架外的迷雾等着我们。同时物理学的发展也越来越受到人类观测水平的限制。只有靠观测靠实验,才能找到更多关于世界真相的线索,然而观测和实验却越来越难做,越来越受限于技术水平。也许真的存在一个类似常量C的人类认知上限,将人类紧紧约束在其中。在未来,世界的真相,只有靠哲学家们去猜测。

 

 

 

从磕头说起

每每打开电视机,看见到处都是清宫辫子戏、穿越剧,四哥、八哥,满嘴奴才、奴婢,动不动下跪磕头请安,不禁感到反胃。

20101130141852846与世界其他民族的单膝下跪相比,中国人的跪有点特殊——双膝下跪。因为中国人的跪源于“正坐”这样一种双膝着地的坐姿,五胡乱华之前,中国人并不坐凳子,大家平时正坐着都是双膝着地,和现在日本人比较像。

而屁股撅老高,脸贴地磕头的这种君臣礼仪是何时开始兴起的呢?康有为有一句精辟的总结:“汉制,皇帝为丞相起,晋、六朝及唐,君臣皆坐。宋乃立,惟元乃跪,后世从之。”。可见跪礼的兴起是在蒙元时代。当时的跪拜在蒙古人的高压统治下,变得不可收拾,从原本最庄重的谢礼,变成了见面礼,见到级别比自己高一点的官员就要下跪。“崖山之后,已无中国”,在南宋的崖山之役之后,汉人失去了最后的一点抗争勇气,丧失掉了民族之魂,从此衰败。

在汉人最后一个王朝,明朝里,跪礼总算有了改良,只是在官员三年一次的觐见,或者殿试等庄重场合。然而,受到蒙古人奴役摧残的汉人,在汉人王朝里,依然显示出了野蛮暴力的一面,继承了蒙古人带来的两种刑法:廷杖、凌迟。不管如何的光怪陆离、礼崩乐坏,大明依然是汉人最有血性最刚烈的王朝。一不搞和亲,二不签条约,谁不服,打痛为止。天子守国门,君王死社稷。当崇祯留下“任贼分裂,无伤百姓一人”的豪言自缢殉国的时候,他不会想到,三百年后同样的亡国之君溥仪却在舔倭寇的屁眼,卖国求荣。皇帝都在卖国,匹夫有爱国的理由吗?

在汉人被满人奴役之后,一切都变了。留发不留头全民带辫子;磕头变成了见面礼;君王可以动不动把大臣拉去砍了;满臣自称奴才;而汉臣连称奴才的资格都没有!

对于把蒙古的元朝和满族人的清朝当成中国人华夏自己的朝代,实在是有待商榷的。首先两朝的官方语言都不是汉语。蒙古皇帝从来都不懂汉语。满族皇帝虽然会说汉语,但是官方文件以及外交签署的协议,比如尼布楚条约,也都只有满语版,没有汉语版。中国这片土地其实是蒙古人和满族人被征服被奴役的殖民地。蒙古人的成吉思汗不是中国的成吉思汗,满族人的皇太极也不是中国的皇太极。可以想象,如果日本当年侵华成功,日本人在中国领土上建立的新帝国,也不能算是中国的帝国。印度人被大英帝国殖民奴役了几百年,也没见人家印度人厚着脸皮在历史书里说一句,“我们当年的伟大王朝大英帝国日不落是如何的厉害”之类。

事情过去了几百年,现在的中国只记得日本人的侵略,却忘掉了满族人当年做过的事了。甚至于受政治导向影响,还有歌颂清朝圣皇丰功伟绩什么再给我五百年的各种电影电视剧在进行洗脑教育。让我们来看看除了磕头跪礼之外,满族人还做了什么:

20111231213143-304892087满族人对包括汉族的所有其它民族对进行了野蛮大屠杀:

  • 入关后满清把近两亿汉人屠杀到了四千万。扬州十日、嘉定三屠。除此之外还有四川、东北、广州大屠杀。在以后的近三百年来,大规模的屠杀更是一起接着一起,受害者比以往两千年历次屠杀加起来都要多。更加比抗日战争里的死亡人数要多的多。
  • 满清对蒙古族厉行减丁政策,蒙古各部只要超过男丁上限,那么就要靠抽签来杀死多出来的男丁以进行减丁。这种无差别屠杀甚至包括爱新觉罗家族的铁杆科尔沁蒙古,科尔沁蒙古的男丁上限是八万,顺治和儿子康熙屠杀起科尔沁来也是一样不客气。短短四十年里,仅科尔沁蒙古的男丁,他们父子俩就屠杀了三十万。
  • 满清对回族各部进行了持之以恒地种族灭绝工作,并制定了“以回牵汉,以汉制回”的政策,极力挑拨种族仇恨。鼓励回汉种族仇杀。这个影响到今日还没有消除。

满族人对汉族人的文字,以及文明,进行了长达二百多年的灭绝:

  • 明朝有着辉煌的音乐艺术成就以及科学发现和探索,比如十二平均律就在明朝被提出,比如中医也第一次提出人是用脑而不是用心在思考——不过它失去了进一步发展地机会,因为这些新理论被满清禁毁了。明朝翻译了几何原本……明朝的妇女都知道地球可能会是圆地并为此展开争论、还为此写下笔记……明朝有人准备写下技术书籍,介绍如何炼钢炼铁——这些书籍都被满清禁毁了。
  • 顺治平均每年发动一次文字狱。他儿子康熙平均每五年一次,他孙子平均每两年一次,而他重孙子乾隆,竟然平均每年发动两次文字狱!
  • 1061文字狱搞黑名单显得很不过瘾。乾隆准备好了白名单——四库全书,宣布华夏只有三千本书是可以存在的!禁毁而留书名则有近七千本,至于禁毁而不留书名的更是不计其数——天啊,不要说煌煌两千年华夏。仅在明朝、仅天启皇帝批准刊行的书籍就有两万余本!大量的古籍在清朝绝版。大量的祖先留下的文字咱们再也看不到了。
  • 四库全书里对大量文字进行了篡改,其中有史书,甚至各种文学作品包括岳飞的满江红。直到如今我们看到的古籍中,如果找不到清朝以前的版本,也很难找出来哪些是没有被满族人修改过的。
  • 翻开满清的历史,除了“屠杀”外能看见的就只有两个词:愚昧、卖国——从满清开始。直到1911年辛亥革命前,世界史上再也没有一个中国籍科学名人、没有哪怕一项属于中国的技术发明;这个政权在二百多年的统治期间,竟然签了一千一百个卖国条约,平均每年要签三个!

让我们回到下跪这个话题,来看看愚昧又野蛮的满清是如何对待外国人的。这里不得不先说一说,外国人最初是怎么看东方的。

早在15世纪,欧洲就流传了一本包装成游记的小说《马可·波罗游记》。这本书首先不是马可·波罗写的,再次,马可·波罗这个人是否存在都存疑,最后,这本书作者压根就没去过东方,完全是道听途说。但是架不住书里写的美好:在伟大的蒙古大汗统治下的东方遍地是黄金,如果人间有天堂,如果圣经里的伊甸园真的存在,那么它就在东方。这本书影响了整整几代欧洲人,成为欧洲销量仅次于圣经的畅销书。

e1c0d0a366b027935c02fe49350269cd欧洲人看了《马可·波罗游记》就起了来东方掠夺的想法么?和中国历史书的说法恰恰相反,当时他们看书的时候是自惭形秽的。直到18世纪末,大英帝国初步建立了日不落帝国的地位,一直渴望和强大中国结交的乔治三世开始觉得自己是不是有资格了?于是他派出了马噶尔尼伯爵组建了庞大的使团,光礼品就花了整整一年时间准备,总计价值达到当时的一万三千英镑,装了整整六百箱。英国认为这份礼品能够显示出欧洲的工业革命成果,先进科学技术,并且能给东方皇帝一些启迪。这些礼品包括:完整的蒸汽机、棉纺机、梳理机、织布机、欧洲最先进的天体运行仪、当时世界上最精确的地球仪、英国当时最先进战舰——君主号的模型、榴弹炮、卡宾枪、连发手枪、步枪、现代炮兵装备、赫哲尔望远镜、一套英吉利大型图册、秒表、热气球、车辆、油画。

可以这样说,这些礼品的集合,相当于大英帝国把自己的科技博览会开在了满清的国门之下!经过几个月的航行,这样一支满载着友善和诚意的使团终于到达了东方,然而面对他们的是一次非常尴尬的鸡同鸭讲的接触。

db7321f429bcbadef2d38595当时马噶尔尼伯爵想给乾隆宠臣福康安表演欧洲火器操,检阅带来的英国使团卫队,演习新式武器,福康安的回应是:“看亦可,不看亦可。这火器操法,谅也没什么稀罕”。陪着使团而来的热气球驾驶员,居然连一次热气球升空的机会也没有给。更让英国人想不到的事情是,他们带来的让他们引以为傲的代表先进文明的礼品,乾隆为了表示蔑视,把他们都堆放在一间厕所里。他们最后也没有想到,让乾隆不高兴的原因,就是因为马噶尔尼伯爵没有对他行三拜九叩大礼,只是做了欧洲拜见君主用的单腿下跪礼。

在回到英国之后,马噶尔尼在文字中评价愚昧又野蛮的满族人道:“中国自满洲鞑靼占领以来,至少在过去一百五十年里没有进步,或者更确切的说反而倒退了。”“满洲人打仗爱用弓箭,当我告诉他们,欧洲人已放弃弓箭而只用来复枪打仗时,他们愕然不解,认为在奔驰的马上射箭,比站在地上放枪豪迈。”。

之后的阿美士德使团也遇到了类似问题。当时的嘉庆帝特意在阿美士德进京前,对使团进行三拜九叩的培训,并且要随时给嘉庆汇报培训的进展和英使团的态度。这个举动又遭到了阿美士德的坚决反对。最后谈判的结果是,阿美士德也只同意行单膝下跪礼。于是这次外交又遭到失败。

俄罗斯人还有更早关于下跪的故事。1676年,斯帕法里率领俄罗斯使团进入中国境内,为确认身份,拿出康熙写给沙皇的信件,大批满清官员如遭雷击,面向康熙的手谕齐刷刷跪倒在地,令斯帕法里目瞪口呆。他在后来的《中国札记》里写道:“他们竟有如此不分场合的、奴隶般的举止,实在是我所见过的最为卑贱的鞑靼。鞑靼的政府由一群奴才组成,他的国民羸弱不堪……鞑靼皇帝丝毫没有什么可惧怕的。”

哲学家罗素后来评价磕头事件,说道:“当我们不把磕头当作一件可笑的事情时,我们才能真正了解中国”。英国报纸评论说:“这就是中国人,昔日人类无与伦比的精英,今天已沦为人类学研究的怪物。”。愚昧的满清用“磕头外交”拒绝了一个又一个带着友好和诚意来的欧洲使团,最后自绝于舰队和炮火之中。

1315786837_PFKsyX书页翻回现代,在如今新社会下,屡屡还有中国人要恢复磕头这一鞑子皇帝强行奴化汉人而推行的“古礼”。继2007年“疯狂英语”的推广者李阳闹得沸沸扬扬的学生集体“下跪”事件之后,2008年1月20日,央视播出了这样一幕:著名学者季羡林正襟危坐,接受弟子钱文忠的跪拜大礼;2月11日,笑星赵本山公开举行收徒仪式,接受35位徒弟的集体跪拜。更有之后的老中医接受徒弟跪拜收徒等等。

有人用自由来给下跪辩护,认为下跪是徒弟们的自由选择。在完全自愿的情况下,跪拜并不违反法律,看上去除了当事人,并没对其他人造成影响或损害,但是否违背了自由的原则呢?一个,或几十个、上千个学生集体下跪,严重损害学生人格尊严,破坏现代教育的核心价值:人格的独立和平等。这是对社会基本道德规范的挑衅。一切道德和法律的建设,最终服务于人的自由。即使学生完全出于自愿跪拜,也无法改变这个事实:对人的自由属性的侵犯。

蒙古和满族鞑子带给中国人的,经过了几百年时间的沉淀,就剩下了奴化和愚昧,而做为当代中国人,要找回崖山之后就丢掉的民族之魂,需要走的路还很多很多。

 

你们的都是我们的

想必看本博客的人,一定都经常混迹于网络,都听说过韩国高丽棒子的各种“无耻言论”。比如“韩国为汉字申遗”,“韩国为风水申遗”,“韩国教授考证孙中山是韩国人”,诸如此类。好笑的同时也不禁让我们产生疑问,韩国人真的这么无聊可耻么?

x稍加搜索其实就能发现,这些新闻都是中国的一家小报,两三个人编出来的。这家报纸叫《新快报》。这家报纸原本没什么人买,报纸主编日日为销量发愁,某天一编辑献计,编造新闻抹黑韩国,主编大悦。随后一则又一则非常雷同的新闻就这么炮制出来了,内容大概就是“中国人的都是韩国人的”,比如孙中山、孔子、风水、汉字。这些新闻的影响力大家都见识过了,各大门户媒体纷纷转载,网民们津津乐道。影响力大到连韩国报纸、韩国大学、韩国驻华使馆都出来纷纷辟谣,可悲的是,辟谣消息却没有媒体报道,也没什么人看到,反倒是谣言知道的人越来越多。原本以为只有愤青才会为这个新闻买单,结果连当初的小报主编都没想到,新闻变成网民心目中的“即成事实”了。平日茶余饭后必谈韩国人的笑话,大家欢欣鼓舞喜笑颜开。同样高兴的还有《新快报》报纸的主编,销量上去了,报纸影响力也提升了。如此被冤枉的韩国人的笑料变成了中国人的笑料,上演了一出让人啼笑皆非的人间闹剧。

殊不知,韩国人的“你们的都是我们的”都是中国人自己编造的。而某个历史更悠久的国家在几百年前就开始了“你们的都是我们的”的考证。

故事要从一个原本普普通通的意大利人说起。

这个人是意大利省长的长子,可以算是比官二代更厉害的太子党吧。从小就特别聪明,不管什么书看一遍就可以过目不忘。原本省长父亲是想让儿子好好念大学以后子承父业做官,但是这个人在朋友的引导下皈依了天主教,辍学去念了神学,投靠了伟大的主的怀抱,把父亲气的够呛。

某一个阳关灿烂的下午,教皇召见了他。然后大概发生了下面对话:

“你可愿为将吾主之光辉洒向世界的每一个阴暗角落而奉献一生?孩子”

“这是我毕生之心愿,殿下!”,他虔诚的匍匐在地上。

“地球的另一边,在遥远的东方,有一个庞大的帝国,无信而又愚昧,你可愿去帮助吾主驱除黑暗?”

“如您所愿!在吾主之光辉沐浴下,黑暗必将驱散!”

于是,这个年仅25岁的意大利小伙儿,为了毕生的信仰,义无反顾的离开了家乡,去了一个极其遥远又极其陌生的地方,进行极其艰难的传教事业。遥远到远在万里之外地球的另一端;陌生到需要面对一个语言不通没法交流的封闭群体;艰难到一旦说起传教就会变成过街老鼠人人喊打。

他去了遥远的东方一直到死都没有回过家乡意大利,在那里度过了后半辈子。

li这个人就是意大利传教士马蒂奥·利奇。他还有一个中国人极其熟悉的中文名字:利玛窦。

十六世纪的旅行,可不像今天那样,可以随便在某个周末早上跑到世界某个角落去喂鸽子。利玛窦和他的老师罗明坚以及另外十四位神父,先去了葡萄牙的里斯本,等了几个月等到前往东方的船只,然后在又小又闷的船舱里住了半年,好在没有发生传染病和瘟疫,但是等他们到了印度果阿,大家疲惫不堪,不得不又养病休息了几个月。

过了4年,利玛窦终于接到了命令,和老师罗明坚一起前往澳门。当时同行的神父都觉得在中国传教希望十分渺茫,因为明朝甚至规定所有西夷(洋鬼子)没有”路照”禁止进入广州。但是他和他的老师依然在澳门艰苦的学习着中文。他的老师当时已经36岁了,学习中文十分的吃力。当时可没有字典或者翻译!极其封闭的中国甚至找不到一个会外语的人,学习中文的唯一办法就是把东西画下来,找当地人问发音,然后一个词一个词的模仿。

又过了一年,师徒俩总算找到机会,联系上了肇庆知府,谎称自己是来自天竺的僧人(当时中国人觉得天竺就是了不得远的地方了),于是混进了广州。在广州肇庆,他们一边筹钱,一边兴建在中国的第一座天主教堂:仙花寺。当然,这是披着佛教外衣的天主教堂。然而好景不长,6年之后,广州总督经过人举报发现了他们传的不是佛教而是基督教,于是被驱逐出了肇庆,连好不容易造好的西式教堂也被广州总督霸占。利玛窦开始意识到,如果没有中国皇帝的允许,在中国传教是一件多么多么艰难的事情。

这时候他的老师罗明坚也回了意大利,只有他留下来继续传教。之后的12年,利玛窦认准了一个死理,就是必须去北京定居传教,从中枢影响这个国家。利玛窦找了种种机会去北京,期间遭遇了普通人难以想象的各种艰难险阻。第一次去,最远只到了南京,回来大病一场。第二次去,因为遇到了日本和朝鲜打仗(不可抗拒之力)又被迫回来了。第三次去,又被一个贪婪的太监抓了起来,打了一顿,然后关押了1年。后来利玛窦总算学会了中国官员的那套,给银子上下打点各种达官贵人,带着大量的贡品:自鸣钟、圣经、万国图志、大西洋琴,面见了皇帝。皇帝看到这么多新鲜玩意儿龙颜大悦,准许了利玛窦永久居住北京。

可见几百年前一个北京户口对外国友人的吸引力之大!12年光阴,无数金银财宝、稀奇玩意儿,各级官员上下打点,经历了强盗劫匪,疾病困苦,朝鲜战争,宦官发难,牢狱之灾,最后户口总算办下来了!

利玛窦期间为了能融入中国的仕族圈,不停的宣扬西方的科学知识,西方的文化。外加利玛窦的记忆力超群,他期间写下了很多书籍,同时还把中国的四书五经翻译成了拉丁文。

map利玛窦此举其实是无心,只是一个为了融入这个社会的手段。他带到东方的东西也不是什么稀罕玩意儿——世界地图:西方满大街都是了;天文学:哥白尼都死了几百年了;几何原本:西方的初级课本而已,是1800多年前的欧几里得写的。但是这些书籍和知识对当时的中国知识分子带来的冲击是非常巨大的,因为这些是第一次传进古老的中国。中国人第一次知道了原来地球是圆的而不是方的!地球是绕着太阳转的!原来阿尔朱巴尔(algebra 代数学的另一种翻译)这么高深复杂!原来几何是这么的深奥!

你一直在用诺基亚黑白屏手机,忽然有一天你发现邻居在用先进的iPhone5,比你的领先几个时代,你会作何反应?

  1. 努力奋斗好好赚钱卖肾买一个iPhone5去。
  2. 诺基亚就是好用,就是耐摔,我就喜欢用。你们爱用什么用什么,我不稀罕。
  3. 好贼子!这不就是我去年丢的那个破西门子么?你别以为你给染个颜色加个边框我就不认识了?

当时的中国知识分子从利玛窦那里看见了自鸣钟、世界地图、几何原本之后,大体也就是这三种反应。不过可悲的是,自尊心极强的古代知识分子们,大多数都选择了第三种办法来应对。

其中最正常而且明智的人莫过于徐光启了,他选择的是第一种办法。徐光启在看到这么多先进东西之后,喊出了震耳欲聋的口号:“如果想超越,一定得先学懂。如果要学懂,一定要先翻译!”。徐光启带领其他一些知识分子开始第一次主动的学起了外语,翻译起了外文书。徐光启带头翻译了利玛窦带来的18卷几何原本里的前6卷,还给了评价说:“所有的中国人都应该来学几何原本,如果这本书能学精通,那什么学问都可以精通,如果这本书可以学下来,那什么学问都可以学下来”。然后呢?没有然后了。徐光启的话被绝大多数中国穷酸儒们置之高阁,中国知识分子随后开始了轰轰烈烈的鸵鸟学潮。

0912291105_5让寒窗苦读的酸儒们抛弃四书五经,来看几何原本、代数、天文、农业、政治法律学,必定是极其困难的。但是他们最擅长的是研究古书,从古书海里找出一丝半句的牵强附会的依据来证明说明什么。其中黄宗羲、王锡阐无疑是个中高手。据他们的考证,这些个代数几何,都是从中国传过去的!黄宗羲说:“中国的古籍有《周髀算经》,里面有勾股之术,这不就是几何么,我们现在失传了,但是被西人窃取了而已”。王锡阐更有意思,说:“屈原的诗《天问》里就说过圜则九重,你们看了这个才开始研究天文学的”。还有更可怕的,比如“《诗经》里就提过民主的概念,你们西人不过是看了有启发而已”,“自行船千里镜不过是看了我们古书,仿照诸葛丞相的木牛流马而已”。各种奇怪的考证不一一列举,总之华夏文明依然是天下第一!你们现在虽然先进,不过是偷了我们老祖宗的!

这些知识分子不去学习一句半句外语,不去继续翻译外国人的书,而是一头钻进了中国浩如烟海的古书里,从里面找西人窃取古人的新证据!

这些人还包括了赫赫有名的方以智、顾炎武、王夫之、梅文鼎、颜元、毛奇龄、胡渭、阎若璩,以及后来的戴震。不过这些人加在一起也没有一个人的力量大,这个人就是康熙帝。

康熙很喜欢西学,他接触过很多传教士,甚至自己对代数有一点研究。某一次康熙下江南,接见了当时的学派领袖梅文鼎,两人在运河上泛舟三日,相谈甚欢。康熙给西学下了定论:“西洋的算法确实是厉害,不过以前也是中国的算法,后来传到西洋才叫阿尔朱巴尔(代数),其实是源自中国。”康熙还自己写了一本《三角形论》,大谈西学东源之说。

有了皇帝带头,手下当然更积极的找证据了。清朝期间找到的各种文献古籍无数,举不胜举。到了乾隆编著四库全书的时候,一个叫戴震的更加荒唐,写了一本《勾股割圆术》,这其实是一本西学的书,但是他把西学的词全部用古语替换,号称三角学都是从中国古书中推导出来的。

这个普通的虔诚传教士利玛窦,估计做梦都没想到,他最初为了传教带去中国的几样普通玩意儿,给东方这个腐朽的帝国带去如此大的震动。然而这潭水太深了,一些现代科学的火种很快就被淹没。世界地图偶尔看看图个乐子感慨一下原来世界这么大,自鸣钟被放进皇宫里没有维修很快坏了,那些科学著作都被考证原来是抄袭咱们老祖宗,没啥大不了的了。

是不是只有愚昧的清朝学者如此,到了近代这个“你们的都是我们的”理论就没法落脚了呢?其实不然。

中华文明自以为天下第一的不求上进,使得这个文明在之后的几百年一直在被欺负挨打,惨痛的教训让之后的中国人舔了几代人的伤口。在真的实现现代化接触了世界文明之后,才发现其实很多东西我们依然被欺骗了很久。

其中不得不谈到一个英国汉学家李约瑟。之前那么多古人编造的西学东源故事,恐怕还没这个人一个人加起来的多。1942年,中国对日战败,绝大多数中国领土沦陷,蒋介石逃到了重庆,全国一片哀号。这时候汉学家李约瑟出现了。在蒋介石的资助下,李约瑟在重庆1943年搞出了“四大发明”的成果,在抗战时期大大提升了广大军民的民族自豪感和斗志。张召忠将军评价李约瑟的这个成果”抵得上共和国卫队10个师”!

cover_715099_556_big1947年李约瑟回英国开始专心写书,1954年发布了一本奇书《中国科学技术史》,帮助中国人民总结了过去2000年中国所有的科学技术,让中国人大吃一惊,原来我们的老祖宗这么厉害过!

从此四大发明成为一个可笑的玩意儿,中国人关起国门来孤芳自赏引以为豪的东西。外国人从来也没有承认或者认可过,只有在中国官方肯定并且玩命儿似的宣传。

李约瑟的书以及四大发明的问题,请大家搜索一下必然能找到很多答案,这里略举几个例子,比如沈括《梦溪笔谈》只是一本奇闻录,活字印刷在中国从来只是传说故事。《中国科学技术史》说,中国人最先发明了机器人,因为汉朝就有关于陈平造木头人会跳舞的传说。还有,中国人最先发明了直升飞机,因为有古文记载某种竹蜻蜓能载人的故事。再比如二进制是易经里早有叙述(八卦,64卦能叫二进制么?),莱布尼茨可能是看了《易经》才得到启发。其中反复引用培根的话证明四大发明,但是培根和马克思也从来没说过四大发明是中国的,相反马克思说到中国是一个科学技术的贫瘠之地。

后来又过了很多年,另一个作者罗伯特·坦普尔在1986年,完全遵从李约瑟的大作,搞出来一本《中国的一百个世界第一》,成为中国儿童的科学启蒙教育书,这真是非常可悲的事情。

中华民族有着璀璨的历史,不用妄自菲薄,也不能随便拔高古人。现在被写进教科书里被吹嘘过头的各种古人的科学发明成果实在是数不胜数,比如指南车、地震仪、司南,等等(这些东西的作假证据就不一一给链接了)。中国古人确实是科技贫瘠,但是古人的手工业水平和制造业水平还是相当的高的。如果只是为了证明古代科技也曾经辉煌过,而胡编乱造,找一些野史传说来瞎凑自欺欺人,然后培养国人所谓自豪感,无疑是非常非常可悲的。

中华文明的未来需要我们去努力创造,不迷信古人,不吹嘘历史。

不要学被我们冤枉的韩国人——“你们的都是我们的”。

 

圆周率之随笔(3)

今天是圆周率节,赶工怒发博文!

在古代,为了计算高精度的圆周率,数学家们往往要用纸和笔辛苦计算几个月甚至几年。而今天我们点点鼠标就可以悠闲的分分秒把圆周率计算到几百万甚至上亿位。这一章我们来看看,在现代计算机上,如何在最短时间里计算出最长的圆周率。

不少人想到计算圆周率可能会联想到Superpi这个邪恶小程序。这个程序是日本人金田康正在1995年写的,可以在家用电脑Windows系统上把圆周率计算到3000万位。国内很多的装机商攒机商,都用这个程序来测试新装机的超频性能。这其实是很不科学的。首先这个程序是1995年开发的,距离今天已经有快20年,不光算法过时,编译器也已经过时,很多新CPU的特性都没有利用上。第二,这个程序是用单线程开发的,现代CPU动不动就是4核8核,单线程的计算程序早已经无法反应CPU真实能力。第三,单一的用Superpi做超频测试,也容易让硬件厂商进行有针对性的作弊。现在其实有比较新的 Hyper PI 可以做为Superpi的替代品。

Superpi 和 Hyper PI 远远不是现在在家用电脑上计算圆周率的主流和先锋。他们采用的高斯-勒让德算法也早已过时,有更好的可以替代。

由于圆周率的计算算法实在是五花八门,如果都总结下来的话,作者可能可以骗几十章博客更新,读者可能也懒得再看直接关窗口。那么这里只说一个目前为止最先进和最好的算法。这就是楚德诺夫斯基(Chudnovsky)算法。

楚德诺夫斯基是生于乌克兰的美国数学家,1992年纽约人杂志把楚德诺夫斯基评为世界上最厉害的数学家之一。1987年他发明的计算圆周率的楚德诺夫斯基算法,一直到今天仍然保持着圆周率的最佳计算记录。

该算法是如何来的,请看专业论文,这里直接给出公式:

826dc7788dba249ee86fc0135e06b035

看上去超级复杂是不是?其实不然,通过简化,代码只有短短的几行。该算法的最大特色就是,整个计算过程只用最后做一次除法和一次平方根运算。其余全都是加法和乘法!

a = lambda i: (1,1,13591409) if i==0 else ((6*i-5)*(2*i-1)*(6*i-1),i**3*10939058860032000,
        (6*i-5)*(2*i-1)*(6*i-1)*(13591409+545140134*i)*(-1 if i%2 else 1))
b = lambda x,y: (x[0]*y[0], x[1]*y[1], y[1]*x[2]+x[0]*y[2])
bs = lambda i,j: a(i) if j-i==1 else b(bs(i,(i+j)/2),bs((i+j)/2,j))
sqrtC = lambda digits: isqrt(1823176476672000*10**(2*digits))
def isqrt(n):
    x,d = 2**(n.bit_length()-1),1
    while d:
        d = (n/x-x)/2
        x += d
    return x

def pi(digits):
    N = int(digits/14.1816474627254776555+1)
    P, Q, T = bs(0, N)
    return (Q*sqrtC(digits)) / T

这段代码在Python 2.X上可执行,运行print pi(100)看看?圆周率的前100位就出来咯。

对于这段代码稍作一些解释:上文看似复杂的公式,其实被拆成了两个函数:a 和 b。整个圆周率计算被简化成了一个mapreduce操作:reduce(b, map(a, range(N)),也就是 N 次 a 运算和 N-1 次 b 运算。为了继续优化,我们设计了 bs 函数,做的是二分切割,将每次计算区域切割两份,然后分头计算,最后做归并。这个计算量其实是一样的,还是 N 次 a 运算和 N-1 次的 b 运算。那么二分切割为什么会运行的更快呢?其主要原因是进行二分切割可以将高精度的大数乘法尽量拖后,执行的层数越低,数字的长度才成指数倍提高。

楚德诺夫斯基算法号称是目前计算圆周率最快的算法,然而这段代码在笔者的电脑上运行计算 pi(10000) 居然要 60 秒之久。问题出在哪呢?经过简单的 benchmark 我们发现,其主要时间消耗在了 isqrt 函数里。由于 python 默认没有高精度整数的平方根操作,所以这个用牛顿拉普森法模拟的平方根操作很慢。

为了快速求平方根,下面我们祭出高精度运算的大杀器 gmp。同时采用python可以用的 gmpy 来加速平方根操作。经过修改的代码如下:

from gmpy2 import *

a = lambda i: (1,1,13591409) if i==0 else (mpz((6*i-5)*(2*i-1)*(6*i-1)),mpz(i)**3*10939058860032000,
        mpz((6*i-5)*(2*i-1)*(6*i-1))*(13591409+545140134*i)*(-1 if i&1 else 1))
b = lambda x,y: (x[0]*y[0], x[1]*y[1], y[1]*x[2]+x[0]*y[2])
bs = lambda i,j: a(i) if j-i==1 else b(bs(i,(i+j)/2),bs((i+j)/2,j))
sqrtC = lambda digits: isqrt(1823176476672000*mpz(10)**(2*digits))

def pi(digits):
    N = int(digits/14.1816474627254776555+1)
    P, Q, T = bs(0, N)
    return (Q*sqrtC(digits)) / T

经过修改的代码也更短更简洁了,只有短短的10行。让我们测试一下速度如何?(需要先安装 gmpy2 的 python 包才可执行)

位数 时间
10,000 0.04s
100,000 0.11s
1,000,000 1.07s
10,000,000 17.76s

20秒内,在笔记本上轻松将圆周率计算到了 1000 万位!1987年在巨型超级计算机上才创造的圆周率世界纪录,在今天的任何一台个人电脑上,都可以轻松碾压了。

然而我们还不满足。这个代码依然没有把楚德诺夫斯基算法的优势发挥出来。楚德诺夫斯基算法最大的优势是可以很好的并行化。在多核时代,单线程运行的代码实在没法体现出CPU的优势出来。

然而由于python的GIL的设计问题,多线程的代码无法很好的利用多核。因此我们用多进程的方法实现了楚德诺夫斯基算法的并行化。下面是在4核CPU的笔记本的运行环境下比较不同进程数量的程序性能。计算位数依然是1000万位:

计算核心(进程数) 时间
单核版本 17.76s
1 18.58s
2 12.66s
3 10.39s
4 9.88s
5 9.79s
6 10.17s

可以看到,通过并行化代码,利用CPU的多核,我们将性能提升了1倍!在计算核心继续增加超过CPU本身的4核之后,性能不升反降,这也是预料之中的事。

有人会问,为什么用4个计算核心提升的性能不是4倍?这里其实牵扯到并行化算法中比较复杂的问题。4核心最理想的性能当然是4倍的提升,但是由于算法本身限制,以及任务细分之后之间的依赖关系,计算核心之间的数据交换,导致最理想情况很难做到。算法中的任务划分也非常有学问,分的太粗会对多内核利用率不高,分的太细又会大大增加进程/线程间的通讯和同步的消耗。这里就不做更深入探讨了。

在这里我们不得不提到 gmp 官方给的一个 C 语言实现的楚德诺夫斯基算法的圆周率计算程序。这个程序对算法细节进行了大量的优化和微调,代码长度接近800行。其中 pgmp 是利用多线程做的并行楚德诺夫斯基算法。有兴趣的同学可以阅读一下代码了解更多优化细节。

单核C: gmp-chudnovsky
并行C: pgmp-chudnovsky
作者的山寨并行Python版: pi-chudnovsky

下面我们用作者自己的无优化山寨 Python 版本和 gmp 官方给的 C 语言版本的圆周率计算程序进行一下性能测试比较。测试环境是一台8核的Amazon c1.xlarge虚拟机。测试位数是圆周率的前1亿位(100,000,000)。

计算核心(进程数) 时间(C版本) 时间(Python版本)
单核版本 242.3s 397.0s
1 309.4s 419.4s
2 192.3s 226.9s
3 159.9s 168.1s
4 137.2s 135.1s
5 137.5s 116.7s
6 130.8s 105.3s
7 129.7s 102.4s
8 126.4s 99.8s

可见尽管作者的 python 实现的山寨程序尽管算法所用的数据结构优化不够,因此在计算核心较少情况下表现不佳,不过在并行化方面还是做的很好,充分利用到了多核CPU的每一个计算核心。100多行的代码用 python 操作符重载的特性来简化了原本应该很复杂的并行算法的编写。

当然,这些还远远没有到极限。关于圆周率计算的竞赛自古到今一直在进行,在互联网时代越发的激烈。计算竞争的平台也从之前的大型机小型机转到了个人计算机。这里介绍一个著名的圆周率项目叫 y-cruncher

y-cruncher是目前的圆周率计算世界纪录保持者,经作者测试,在刚才的同样测试环境下,计算圆周率1亿位只需要 36.9 秒。y-cruncher 的基本圆周率算法依然还是楚德诺夫斯基算法,但是其代码长度已经到达了17万行!由于优化的足够好,其主要的计算上限还是在内存的大小,y-cruncher的实现主要精力也是在底层内存交换、CPU底层特性的利用以及基础高精度算法的优化上。具体细节大家还是去看他的主页吧。

最后,这篇断断续续写了很久的博客总算完成了。由于篇幅关系,关于博大精深的圆周率以及圆周率文化只是浅尝辄止,希望大家看完以后也能和我一样从此喜欢上深邃的圆周率。

 

 

圆周率之随笔(2)

让我们继续上一章的话题。圆周率是不是祖冲之发明的呢?显然不是。圆周率是一个数学常量,是世界存在以后就亘古不变的一个数字。在人类诞生以前,它就存在了,就一直静静的在那里等着聪明人去发现。所以,很多电视问答题的题目都是错的。那么祖冲之做了什么呢?他是世界上第一位把圆周率算到小数点后第七位的人,同时领先了西方1200多年!

01300000214331124022076846267祖冲之是一个小官二代。祖父是修土木的小官儿,自己一辈子最大也就混了个县令。然而却喜爱数学和工程,在和自己儿子的共同研究之下,研究了一辈子出了一本数学著作,名叫《缀术》。这本书写的是啥,也没人知道了,因为后世就失传了。我们看看唐朝人是怎么评价这本书的。当时唐朝将这本书列为数学教科书,给出的参考学习年数是4年。就是说一般学生要学4年才能把这本书看明白。还有更夸张的,唐朝的算学第一高人李淳风说,“这本书太难了,我们都看不懂!所以大家慢慢也就不去看了”。唐朝的另一个算历博士王孝通说,“有人说这本书很精妙,但是其实里面全都是错的!”。据说宋朝还有人拿着此书练书法。传说是在南宋年间失传的。真相到底如何呢?书已经失传,所以就不得而知了。

《缀术》虽然已经失传了,那我们从何而知祖冲之的圆周率的呢?这个描述来自于《隋书》的《律历志》。作者就是唐朝的算学大师李淳风。原文如下:

古之九数,圆周率三,圆径率一,其术疏舛。自刘歆、张衡、刘徽、王蕃、皮延宗之徒,各设新率,未臻折衷。宋末,南徐州从事史祖冲之,更开密法,以圆径一亿为一丈,圆周盈数三丈一尺四寸一分五厘九毫二秒七忽,朒数三丈一尺四寸一分五厘九毫二秒六忽,正数在盈朒二限之间。密率,圆径一百一十三,圆周三百五十五。约率,圆径七,周二十二。又设开差冪,开差立,兼以正圆参之。指要精密,算氏之最者也。所著之书,名为《缀术》,学官莫能究其深奥,是故废而不理。

翻译成白话文就是说,南朝的徐州从事史,祖冲之,非常厉害,把圆直径一丈分为一亿份,周长在三丈一尺四寸一分五厘九毫二秒六忽到七忽之间 (3.1415926 < π < 3.1415927),等等。

这里略让人产生疑惑的一点是,除了唐朝李淳风在《隋书》里提到这么一句之外,翻遍整个中国古籍,都找不到其它任何关于祖冲之圆周率的描述。甚至在祖冲之之后1000多年的所有古代数学家们,也都全部不知道祖冲之能有如此之高的圆周率精度。看下表:

年代  朝代 数学家 圆周率 精度
公元前100 战国 《周髀算经》 3 0
公元前50 刘歆 3.1547 1
公元78 张衡 730/232=3.1467
92/29=3.1724
sqrt(10)=3.162
1-2
公元133 蔡邕 3.125 1
公元228 三国 王蕃 142/45=3.155 1
公元300 魏晋 刘徽 157/50=3.14
3927/1250=3.1416
2-3
公元370 何承天 3.1429 3.1432 2
公元429 南朝 祖冲之 3.1415926~3.1415927
22/7 355/113
7
公元602 李淳风 22/7=3.1429 2
公元1208 秦九韶 sqrt(10)=3.162 1
陈荩谟 3.1525 1
公元1536 朱载堉 sqrt(2)/0.45=3.1427 2
邢云路 3.1213 3.126 1
公元1533 程大位 25/8=3.125 1
公元1611 方以智 52/17=3.0588 0
公元1714 王元启 sqrt(10)=3.162 1
顾长发 3.125 1
公元1728 钱大昕 3.16 1

祖冲之在中国古代2000多年的圆周率史上,如皓日当空那般耀眼,不仅仅是前无古人,而且当真做到了后无来者(西方数学家算出来的不算)。

为何唐朝人写的《隋书》中,明明写清楚了祖冲之的高精度的圆周率,但是后世1000多年,这些个算学大师们一个一个都闭口不提,而且反而用精度更差的圆周率呢?《梦溪笔谈》的作者沈括也因为使用了很差的圆周率,导致做出来的工具很快就坏了。可见后世人完全不知道祖冲之有了如此了不起的研究成果。

本人有下面几个猜测:ri08_01735_0164_p0030

  1. 可能古代算学家根本不重视圆周率。算个大概就不管了。古人的成果也压根没有人去看过。古代的科学基本没有传承。只有现代中国人才从古老典籍里挖掘出一点点古人的辉煌聊以慰藉。如果是这样,真的是很可悲的事。
  2. 《隋书》可能是造假的。唐朝人写的隋书原本早就在历史的尘嚣中烟飞云散了。宋朝刻印的《隋书》留下的又不全,只有残破的几章。目前能找到的最早版本有记载祖冲之圆周率的《隋书》,是明末的毛氏汲古阁本。是不是后人改的?如果是的话,恐怕更加的可怕。

让我们继续推测,祖冲之是怎么计算圆周率的?这已经成为了一个千古之迷。很多人猜测也是和阿基米德一样的割圆法。是的,这是最合理的猜测了,因为在公元400年的古代,割圆法只需要开方根和勾股定理的知识就可以计算。

借助现代的计算机,我们很容易可以模拟当年的先辈是怎么用外接割圆和内接割圆计算圆周率的:

s = 0.5
for i in xrange(n):
    s = (s*s+(1-(1-s*s)**0.5)**2)**0.5/2
t = (s*2/3)**0.5
for i in xrange(n):
    t = (t**2-((t**2+1)**0.5-1)**2)/t/2
r = 6*2**n
print r, s*r, t*r

这段简单的小程序不另作说明了,通过计算内接和外接割圆边长,我们分分秒就能计算出每一次切割能达到的圆周率精度,和计算过程中所需要保证的小数点后的精度个数:

n边形 到达小数点后精度 过程需要保持精度 结果
6 0 2 3.0<pi<3.4
12 0 3 3.11<pi<3.22
24 1 4 3.132<pi<3.158
48 1 5 3.1392<pi<3.1462
96 2 6 3.14102<pi<3.14268
192 3 7 3.141454<pi<3.141873
384 3 8 3.1415576<pi<3.1416626
768 3 9 3.14158389<pi<3.14161021
1536 5 10 3.141590466<pi<3.141597034
3072 6 12 3.1415921056<pi<3.1415937485
6144 6 12 3.14159251670<pi<3.14159292743
12288 6 13 3.141592619364<pi<3.141592722051
24576 7 14 3.1415926450333<pi<3.1415926707020

可以看到,阿基米德在公元前250年,通过切割96边形,那么他需要在计算过程中保持6位的小数点后精度,才可以计算出 3.14102<pi<3.14268 的结果。祖冲之在公元400多年,如果需要保留小数点后7位精度的圆周率精度,需要切割到24576边形,同时计算过程中要保持14位的小数点后精度!

下面再具体列举一下我们的革命好同志祖冲之计算圆周率之艰辛:

  1. 进行12次迭代(也有猜测是从4边形开始隔,这样只要11次迭代),每次迭代都需要计算3次平方根,若干次乘法除法,另外计算过程要保证14位的小数点后精度。
  2. 没有阿拉伯数字。无论计算过程用的是一二三还是壹贰叁,都麻烦的不得了。
  3. 没有算盘可以打。用的是算筹。把很多小树枝放在地上,拨过来拨过去的,拨错一个就完蛋。
  4. 没法合作完成。算法不能并行操作,没法团队完成,必须一个人自己默默的算。
  5. 至少得验算2-3次吧?历史上算错圆周率贻笑大方的人很多。能一次性算对的很难很难。
  6. 用的是毛笔。没有铅笔钢笔圆珠笔。不管是记录中间计算过程还是结果,都得用掉成百上千纸张。

好同志祖冲之如果真的算到第7位,目测按照当时的条件,怎么也得算个三年五载的。为了一个在当时没什么太大意义的高精度圆周率,耗费如此多的光阴,让人觉得有点匪夷所思。

如果是后人伪造《隋书》编造的 3.1415926 ,那么为何要伪造呢?这里也有一些背景知识需要阐述。

c2cec3fdfc039245010022028794a4c27d1e2502明末清初的年代,一个很著名的学派,是西学东源学派。随着越来越多的西方传教士不远万里来到中国,为了传教学会了中文,然后把一些西方科学著作翻译成了中文,其中最著名的是西儒利玛窦,让当时的学者们认识到了中西的差距已经大到可怕了。西学把日历能推算到秒,可以算出地球是个球体,知道地球的大概半径,能够制造精确的钟表。工艺技术的差别,天文地理的差别,基础数理的差别,让当时的学者们无法面对。

但是总是需要去面对的。面对的方式不是说努力学习西文典籍迎头赶上,而是很猥琐的鸵鸟策略。西学东源的主要思想是,你们西学研究的那些东西,我们老祖宗典籍里全都有了,不足为奇!这些学者依靠各种牵强附会的考证,想要证明西算(数学)和西历(天文学)都是剽窃的我们的老祖宗!这些可耻和可悲的考证成果就不一一说了。这个学派一直到清朝继续发扬光大,清朝皇帝康熙和乾隆一边焚书坑儒,编纂删改古籍,最后出了删改后的《四库全书》,一边组织文人搞西学东源运动,接见学派首脑,让这个学派继续发扬光大。恐怕直到北洋舰队被日本打的个落花流水,以及八国联军打进了北京城,才让当时的中国人真的觉醒,才让他们能够发现,中西方的差距已经实在是太大了,赶紧老老实实的“师夷长技以制夷”吧!(虽然最后也没能制得了夷)

在明末刻印的《隋书》版本,是不是有经过算家的修改,也不得而知了。真相早已掩埋在历史长河中。本文的目的也不是要考证祖冲之是不是算了圆周率,只是把一些证据陈列出来,信者自信疑者自疑吧。即使祖冲之确实算到了第7位,但是后世数学家们的表现也让人不禁感慨,古代对算学这些奇技淫巧的忽视。伟大的人物昙花一现,只有后世西学传入之后,才让人真正了解他们的伟大的地方。

随着电子计算机的诞生这几十年,圆周率的计算长度已经开始几百倍几千倍的增长了,每天都会有新纪录诞生。下一章我们回到正题,谈谈圆周率的常用算法。

 

 

圆周率之随笔(1)

有人说,爱像圆周率,无限不循。那么,读懂了圆周率,你就读懂了爱:简单而又深邃。(这其实是标题党,第一句总要吸引人吧)

圆周率的定义很简单:一个圆的周长除以直径,就是圆周率。然而,圆周率已在人类世界存在了千年,至今还有很多关于它的谜团存在。

Pi-unrolled-720从人类文明有记载开始,远古文明就开始用 π = 3来开始大致计算圆的周长了。如果你不幸被穿越到异世界,怎么确定这个世界的第一常量,圆周率呢?很简单,拿一根藤条,先在地上靠一个支点用固定半径画出一个圆,然后用同一根藤条对着周长比划一下,看看是不是 3 根藤条的长度然后多一点点。如果是,那么恭喜你,你至少在一个常量一致的异世界里!

622762d0f703918f1e9863ba513d269758ee3d6d55fbe449圆周率比3多一点点。多这么的一点点到底是多少?远古文明从人类诞生就开始了探索。公元前1900-前1600的古巴比伦人,在一块后来被发现的破泥板上刻下了圆周率大概是 25/8 = 3.125。这大概是有文字记载的最早的圆周率。与此年代悠久不相上下的是古埃及人,曾经在一张后世被拍卖成天价的破草纸上写下的公式:(16/9)= 3.1605。这个时代我们华夏的古老祖先,还在黄河流域治水灾,没有留下任何文字的烙印,只有一些口口相传的神话故事。中华文明直到大概是战国时期(年代不明,可能是公元前300左右吧)的《周髀算经》里,第一次提到过圆周率:“径一周三”。

Domenico-Fetti_Archimedes_1620

之后的某一天,地球上一个在树下被苹果或者梨砸中的天才忽然想,为什么不能用圆内接的多边形来计算圆的周长呢?最开始这位天才挑中了六边形,因为六边形是边长和半径相等的特殊多边形。然后通过分割,把六边形切成十二边形,然后是24、48、96边形。随着边越多,多边形的周长也就和圆的周长越来越接近了。这位天才就是阿基米德。这个计算方法就是割圆法。

通过计算了96边形的周长,阿基米德给出了 π 的范围:223/71 < π < 22/7 (3.1408 < π < 3.1429)。在公元前250年时代,这是一个极其惊人的成就!可以说,亚里士多德、阿基米德等先贤辈出的古希腊科学家,在距离现今的2000多年前(比我们想象的早很多的时候)就奠定了西方的科学基础,中西差距就此拉开,然后越拉越远。从那个远古时代,西方科学家的地位就变得无比崇高,科学的火种就此被点燃了,然后越燃越旺,最后迸发出难以想象的活力。

而相比之下,中国同时期战国时代的先贤的追求就很不一样。诸子百家都是周游列国为君王出谋划策,以实现他们的政治理想,不管他们是不是什么思想家、教育家,他们首先都是政治家。了却君王天下事,赢得生前身后名,是他们最大的心愿。孔子对国王说的是:“君君,臣臣,父父,子子”;相比之下,同一时期,地球另一边的欧几里得在给国王讲几何学,同时嘲讽国王太笨学的太慢:“在几何学里,没有专为国王铺设的大道”。其追求不同如云壤之别。

除了计算圆周率,牛人阿基米德还在各个领域都有跨时代的突破,以及留给后世诗人们传唱的数不尽的传说故事。其中最著名的一个,就是他在浴缸里洗澡,忽然想出了浮力定律,激动的冲出浴池去裸奔的故事。

300px-Archimedes_Heat_Ray_conceptual_diagram.svg做为皇亲国戚阿基米德,据说为人疯疯癫癫,可以从裸奔一事里窥见一斑。阿基米德的另一个著名传说故事是,为了防守祖国叙拉古城邦,让士兵用了很多很多面镜子,将罗马的海上无敌舰队全部点燃,导致罗马落荒而逃。这个故事是在400多年后(公元2世纪)出现在罗马诗人卢坎的诗集里。然而充满质疑精神的西方,后世有很多人做过各种实验怀疑这个故事的真实性。在1973年,希腊科学家组织过一次实验想要重复阿基米德的故事,之后在2005年麻省理工学院的学生,甚至在2010年12月,美国总统奥巴马都赞助组织过几次类似实验。所有实验结论证明,这个传说故事很可能是假的。古代的铜镜由于反射度不好,外加隔着这么远的大海,除非船只都在那里一动不动,否则很难被镜子点燃。更可能的是阿基米德用他发明的投掷车,远程投掷燃烧弹的办法打败了罗马舰队。

这里不禁感慨一下中西文化的差异之大。西方文化里,质疑先贤是时代进步的象征,阿基米德的故事都可以拿来推翻;而东方文化里,在孔子儒家的法先祖的教育下,崇拜先贤才是思想上正确的,质疑古人被认为是不敬不尊重。

可悲可叹这位伟大的天才人物,最后死在了一个率先攻入叙拉古的罗马士兵手中。阿基米德在看到很多罗马士兵冲进房间之后,依然疯疯癫癫的说:别动我的圆!随后,阿基米德死在了听不懂希腊语而恼羞成怒的罗马士兵手里(或者他听懂了希腊语,但觉得阿基米德是在表现科学家的高傲)。可见阿基米德临死前可能还在研究圆的问题!

一直到公元1400年以后,西方进入了文艺复兴时期,科学技术忽然开始了蓬勃发展,随之而来的是 π 精度日新月异的提高。奥地利人Christoph Grienberger在1630年用多边形法将 π 计算到了38位,这也是阿基米德发明的多边形法的终极记录。随后便进入了级数展开的圆周率新时代。

在中国,街头采访问祖冲之是做什么的?大多数人都会说,祖冲之发明了圆周率。还有某一次电视知识竞赛里,电视节目也给了类似问题:谁发明了圆周率?答案是祖冲之。这个问题应该怎么答?祖冲之和圆周率有什么关系?咱们下一篇再见!

 

谈谈Zopfli

image01

最近 Google 出了一个新的开源项目 Zopfli。Zopfli是什么呢?简单说是一个 Deflate 压缩算法的另一种实现。推出之后国内国外媒体纷纷报道转载。昨天看到国内媒体的报道 (搜狐IT)中说道:“据悉,Zopfli的压缩率比现有的Zlib高3-8倍。”当时看到了就吓了一大跳,3-8倍这是要逆天啊!赶紧去Zopfli主页看一眼,原来只是3%-8%的提升。国内IT编辑真是吓死人不偿命。

Zopfli到底表现怎么样呢?先看看 Zopfli 自己提供的数据:

测试集 样本大小 gzip -9 7-zip kzip Zopfli
Alexa-top-10k 693,108,837 128,498,665 125,599,259 125,163,521 123,755,118
Calgary 3,141,622 1,017,624 980,674 978,993 974,579
Canterbury 2,818,976 730,732 675,163 674,321 669,933
enwik8 100,000,000 36,445,248 35,102,976 35,025,767 34,955,756

大概是比标准的gzip -9要小 3.7%-8.3% 的样子。但是压缩所需要的时间非常的惊人:

压缩算法 压缩时间
gzip -9 5.60 s
7-zip -mm=Defalte -mx=9 128 s
kzip 336 s
Zopfli 454 s

可以说如果用 gzip 压缩要喝口水的时间的话,用 Zopfli 就可以出去吃个便饭了。

我们再看看这些算法的出生年份:Deflate最早诞生于1994年。7-zip最早诞生于1999年,也是一个开源项目,虽然7-zip自己默认用的格式是LZMA和LZMA2算法,但是也支持对Deflate算法的更好的压缩。KZip 是 Pngout 作者写的一个小工具,诞生于2006年,是一个把现有Zip再压缩的工具。

这里不得不提几个Zopfli文档里没有提到的其它 Deflate 兼容的压缩工具:DeflOpt,是2007年诞生的一个Zip再压缩工具。AdvZip,是一个利用7-zip Deflate的一个Zip再压缩工具。

可以从表中看出,Zopfli比1994年原版Deflate确实有3%-8%的提升,但是对比比较新的Deflate实现,提升实在是很有限,比如比KZip只提升了大概1%不到。压缩时间对比KZip也增加了相当多。

发布没多久,就有人发现,利用 KZip+DeflOpt,压缩的结果可以比Zopfli压缩的更小,甚至Zopfli的几个样本的压缩结果,依然可以用 DeflOpt 再压缩一点(1%左右)。所以说Zopfli其实并不是他在文档里所说的,“所有已知Deflate算法实现里压缩比最高的”。

当然,Zopfli的意义在于它是开源算法,而KZip+DeflOpt这俩都不开源。关于KZip,DeflOpt是如何实现的,之前还有很多人在猜测。Zopfli的出现给大家提供了很好的解答。

另一点值得探讨的是,在今天研究Deflate算法更好实现是否还有价值。Zlib的作者本人Mark Adler在听说Zopfli之后说:“这很酷,不过看上去是一个付出了很多努力,但只取得了很小提升的一个糟糕结果。也许到了给HTTP的accept-encoding加上更好算法的时候了”。是的,诞生于1994年的Deflate确实太老了。现有的解压更快、压缩比更高的开源算法有很多很多,比如 bzip2, LZMA/XZ等等。LZMA/XZ在解压速度上,以及压缩比上,都完胜Deflate。Deflate对于很多 UTF-8 3 bytes的网页压缩效果也很不理想。直到今天,支持bzip2, LZMA的浏览器还寥寥无几。也许更有前途值得关注的是HTTP/2.0协议(一部分基于Google的SPDY协议)。

重新回到Deflate算法。为何Deflate有如此多的压缩实现呢?我们得详细的看看Deflate算法的具体内容。Deflate算法其实就是LZ77算法加Huffman算法。先经过LZ77的字典找重,然后用Huffman树进行降比特。不同的Deflate压缩的实现其关键在于LZ77的搜索重复单词,以及选择分块来进行Huffman。早期算法例如7-zip对分块都不是很重视,更多的考虑的是LZ77算法的优化。而KZip另辟蹊径对分块也进行了优化,使得最终比特流长度变得更短。

LZ77算法优化是一个有向图上的最短路径的搜索问题。对于字节流每个字节建立单边节点,重复单词序列建立更短的边,形成一个有向图。LZ77算法的目的就是如何找到有向图从起点到终点的最短路径。对于边的长度确定的情况下,用动态规划找最优解是很简单的。然而LZ77在搜索时,如果要考虑下一步Huffman过滤之后的长度,则边长度就是不固定的。Zopfli采用迭代的办法,先用一次贪心法拿到第一个次好的结果,然后通过使用结果字节的熵值(就是出现频率的N-log2n)来给出下一次迭代的每条边的边长,也就是每个字母的比特长度。通过反复迭代,来逐步逼近最好结果。当然,理论上也可能跌入一个次好结果的低谷。

Huffman_tree_2.svg然后是最关键的分块问题。分块为何会影响Huffman的压缩结果?其主要问题还是因为动态Huffman算法的随机性。如果都采用对字节使用频率统计完毕之后的静态Huffman,那么不管如何分块都不会对结果有影响,反而因为分块产生额外的比特,使得结果变大。动态Huffman的树是在字节流的处理过程中动态创建的,因此其字节流的开始片段不规律性往往使得结果不优。如何分块才能更优?因为随机性太大,也很难进行判断。所以KZip和Zopfli采用的都是尽可能的穷举。KZip就号称用了“重复单词的穷举(LZ77)”和“更高效率的分块(Huffman)”来实现,可以增加分块的个数进行进一步优化。而Zopfli,是不停的在一个最大块内找9个点,穷举判断哪一个最优,然后进行反复切割的办法。

Deflate压缩算法有没有最优解?这其实是个NP问题。对于短短32字节大小的数据,都有2**31 = 2147483648 种不同的分块方案。当然绝大多数分块都没有意义而产生更差结果。分块之后依然还有需要进行迭代的边长会变化的最短路径问题需要解决。

最后,尽管 Zopfli 的结果不是很令人满意,不过确实给众多不开源的 Deflate 压缩工具树立了标杆。那些想靠着 Deflate 算法做收费 PNG 压缩的软件可以洗洗睡了。