五千年(敝帚自珍)

主题:Dylan Beattie:数字世界的算法原理 -- 万年看客

共:💬3 🌺36
全看分页树展 · 主题
家园 Dylan Beattie:数字世界的算法原理

https://www.youtube.com/watch?v=ukYuhyxXZMc

我出生于1978年的肯尼亚,我出生后不久,我父亲想给我的祖父母发一张我的照片。当时老人家们住在英国。于是他用一台胶片式照相机拍下了这张照片,将底片送去一家药店。两个礼拜之后冲洗完成,装进信封,贴上邮票,然后寄去了英国。从拍照到家住在牛津郡的老人家们拿到照片大约耗时六周。谁想估算一下六周发送一张图片相当于多大带宽?恐怕只有纳米级带宽。

到了2018年,情况当然很不一样了。自从我出生以来,我们从六周发送一张图片进化到了能将图片发送到运行当中的火车上,而且所有人都习以为常。现在这张照片上是我女朋友的橘猫,名叫莱诺。莱诺是这场讲座的主角,我们接下来要将它的形象好好传输、编码与压缩一番——当然,本次讲座当中不会有任何动物受到伤害。莱诺并没从大学毕业,最近也没结婚,只是躺在床上亮肚皮而已。我女朋友觉得莱诺好萌,于是决定发给我一张莱诺的照片。我当时正在坐火车,突然我的口袋里有个装置震动起来,我打开这个装置,看到了莱诺的照片,然后回了一个LOL,因为这就是互联网上应对猫咪照片的正确方式。我们对此已经习以为常了,每天都在时刻这样做。我们发送各种图片、短信与表情,以光速来回横跨世界各个角落,但却从未停下来想一想这一切究竟是怎么做到的。今天我就想讲解一下实现这一点所需的技术、创新、工程设计与算法。

所以说我在英国的火车上——或者在美国,又或者在全世界任何一处被移动数据覆盖的地区——发现自己的手机在线。我知道手机在线,因为手机上显示出了四格信号。这个符号究竟是什么意思?意味着我的手机与离我最近的手机基站建立了联系。要想解释其中的原理,就要理解无线电波。我们从未发明无线电波,而是发现了它。百十年前有人发现,给金属线通电就能产生无线电波。无线电波与X射线、可见光、不可见光、微波乃至我们用来观测遥远星系的宇宙射线都位于同一张光谱之上,这一切其实都是频率不同的同一种波。接下来又有人发现,如果在通电导线附近放置另一根导线,那么第二根导线可以在无线电波的影响下产生电流。我们就这样发明了无线输电。接下来又有人说,假如我们在很高的山上树立一根很长的导线,在导线一头装一个话筒与一个扩音器,就可以用这个装置传输声音甚至音乐。接下来我们还可以造一台半导体收音机来接收这东西的信号。如今我们觉得收音机也没什么稀奇,但是收音机刚刚出现时同样轰动一时。

无线传输的基本原则从那时到今天都没有根本变化:给导线通电,放出无线电波,用另一根导线感应无线电波,将其转换回电流。但是我们都能看出来,接收音乐频段的半导体收音机与智能手机不是一回事。为了从半导体收音机进化到智能手机,我们要解决三大问题。首先,无线电广播是单向的,而我们必须设法让手机在接收基站信号的同时也能向基站发送信号。其次,无线电广播面向所有接收者,而我们不想让其他人一打开手机就能看见你自己的邮件。最后,我们需要远比传输音乐更大的带宽才能让智能手机发挥功用。无线电波传输的原则之一是:传输距离越远,同等电力所能承载的信息越少。为了在耗电量不变的前提下传输更多的数据、带宽与信号,最容易的方法就是缩短传输距离。于是人们设计出了蜂窝网络,将信号覆盖区分为许多蜂窝状网格,每个网格中心有一座信号塔,负责在网格内部广播信号与收发数据。网格大小因地制宜,在空旷乡间两座信号塔可以间隔三四十英里,在市中心恐怕每隔几百码就得修一座。换句话说,手机不必与很远处的信号源建立联系,只需要与几百码之内的信号源相互沟通。请大家拿出手机看看信号满格没有?看来大家都满格了。咱们这屋里得有一二百人吧?在屋顶上肯定有一座信号接收器正在与二百部手机同时进行无线电交流。好好想想吧,如果要你来解决这个问题,你会怎么办?

接下来我们要解决无线电波只能单向通信的问题。我们可以设想单向传输好比一条单车道,车辆可以从这头跑到那头,也可以从那头跑回这头,但是两头同时发车就会相撞或者说信号会相互干扰。一代手机与二代手机采用的技术是划分时段。比方说还是这条单车道,我们规定白天可以从这头到那头,晚上可以从那头回这头。基本上我们将一天分成白天晚上两部分,白天往这头走,晚上往那头走。黎明黄昏禁止通行,从而起到缓冲作用。问题在于很多时候我们并不想等到晚上。于是人们又将时间进一步细分,比如每小时都被分为前半小时与后半小时,前半小时往这头走,后半小时往那头走。接下来又有人想到:“往这头走的流量比往那头走的更多,要不往这头走四十五分钟,往那头走一刻钟怎么样?较小的时间窗口用来发送信号,较大的时间窗口用来下载数据。”很多网络确实是这样操作的。假如你在火车上用三四代手机观看网飞,你的手机其实会相应调整收发数据的时间窗口——当然这里的时间窗口以毫秒计算——使其更有利于下载数据;一旦火车停下来,你打算发送电子邮件,手机又会加大上传数据的窗口,缩小下载数据的窗口。这种设置被称为时分双工(TDD)。

交通问题也可以用更简单的方式解决,既再修建一条路,将单车道变成双车道。这种做法被称为频分双工(FDD),一条信道负责从这头到那头的传输,另一条信道负责从那头到这头的传输。绝大多数现代系统都遵循这一原理,只不过实际修建的车道不止两条,而是十几条,每条车道都有专门用途。当你的手机联系上楼顶信号塔的时候,构成联系的频率大约有十五到二十种,每种频率都担负着特定的任务。例如传输控制信息、确定联网状态、广播传输与组播传输等等。用交通打比方,就好像有的车道专门跑警车,有的专门跑救护车,有的专门送快递。这就说到了第三个问题:我们不希望其他人看到交通情况。你的手机不仅要能够同时进行十五到二十组不同频率的无线电交流,而且要在加密信道上进行交流。我们肯定不希望自己的电子邮件被送到悉尼商务区的所有人面前。于是他们发明了一套非常复杂的加密系统,结合了手机的国际移动设备识别码(IMEI),SIM卡的个人识别码,许多加密合约与轮换密钥,而且整个加密过程都都用不着我们操心。

我们现在有了一套十六种无线电信号,我们可以双向交流,交流内容得到了加密。接下来我们要如何利用这套系统来传输数字信息?年龄偏大的开发人员或许会觉得接下来的噪音很怀旧。这就是数据的声音,是转化成音频广播信号的数据。这是技术史上的一条小小死胡同。二十世纪八十年代,在世界上的许多角落,例如伦敦、德国乃至波兰,曾有人用无线电台广播电脑游戏。他们会挑选午夜时段没有多少人听收音机的时候,然后告诉专门等待的小圈子听众们拿出卡带收录机开始录音。在接下来的二十分钟里他们会播放一款计算机游戏,如果信号足够强,如果不出其他问题,如果磁带长度够用,如果没有干扰,那么你就成为了历史上第一批无线下载电脑游戏的用户之一,下载渠道甚至都不是互联网。将数据转换成音频,将音频转换成无线电信号的做法所能承载的编码信息有上限,我们必须想出将数字信息转换成无线电信号的更有效方式。我想请在座各位体验一下身为发报台的感受。请大家一起击掌。通过击掌我们发出了载波,现在我们要向载波里编入一些信息。当我喊一,大家就用力拍手,当我喊零,大家就轻轻拍手。这就叫调幅(AM)。接下来我们要保持载波强度不变,但是当我喊一的时候大家要将击掌速度提升一倍。这就叫调频(FM),既通过加快与减慢信号发送的速度来表示一与零。还有第三种编码方式,在座各位当中如果有人玩架子鼓的话应该容易理解。现在我们击掌的强度与速度都不变,但是当我喊一的时候大家要与我打的拍子错开。这样做叫做调相(PM)。我们不让信号变强变弱,变快变慢,而是使其提前或者推后。用这三种方法,我们可以让载波表达数字信号。请大家随意鼓掌祝贺一下自己的表现——随意的掌声就相当于信号干涉。

最简单的载波就是正弦波。我们在产生正弦波的圆周上选取两个点,比方说圆周与X轴的两个交点,将右侧交点定义为0,左侧交点——与右侧交点的相位差是180度——定义为1。这样一来就可以通过让载波的状态在同相与异相之间不断转换来表示1与0。但是无线电波承载信息的总量有上限,这个上限被称作符号率(SR),决定了在一定时间内我们能够传输多少符号。假如我们想传输更多信息,要么加大电量,要么增加信道数量——这两种做法都很昂贵——要么让每一个符号都承载更多信息。顺便说一句,刚才这种做法名叫二进位相移键控法(BPSK)。在这一做法的基础上,我们可以在圆周上采用四个点,除了同相点与180度异相点之外,还可以选取圆周与Y轴的两个交点,让这四个点分别代表四个二进制数字:00,01,10,11。这种做法名叫正交相移键控法(QPSK)。更进一步,我们还可以在圆周上选取八个点,表示八个二进制三位数。工程师们给这种做法起了个朗朗上口的名字,叫做四分之π正交相移键控——也正是这些工程师想出了“微软Visual Studio Team System企业版”这个名字。更进一步,假如我们在改变相位的同时也改变信号强度又如何?这一来我们的符号生成器上就有了十六个点位,由此产生的每个符号都能表示四比特信息。这样一来不需要更大电量或者制造更多发报机,我们的带宽就翻了四番,因为我们更高效地利用了原本的空间。这种做法名为16正交幅度调制(16QAM)。更进一步说,如今还存在64QAM调制以及256QAM调制,最后这套系统正是数字有线电视采用的调制方法。所有这一切方法都是为了利用同一套设备与同一个波段获取尽可能大的带宽,因为波段尤其是有限资源,我们早晚有用完的那天。

当你掏出手机时,会看到四格信号全满的标志与4G字样。要想显示这些标志,全靠藏在你手机里的上百个元部件。在你的信息应用当中必定藏着这样一段代码:

while (true) {

msgs = CheckForMessages();

if (msgs. Count > 0) {

PlayAlertSound( );

sleep 1000 ;

}

“若为真则检查短信”,这句话其实跟咒语也差不多。因为CheckForMessages()的基础是超文本传输协议(HTTP)与确保前者安全的安全传输层协议(TLS),这两者又基于旨在保证传送的传输控制协议(TCP)之上,这一协议的基础是不保证传送的网际互连协议(IP);再往下是链路层,确保数据包在装置之间的传输,再往下是4G网络与长期演进网络(LTE),再往下是蜂巢网络,在最底层是无线电波——假装这一切其实都是魔法还要容易一些。我们完全不需要理解所有这些机制就能利用它们。回头再来看看这段代码。检查短信,若短信数量大于零则播放提示音。那么我们怎样让手机发出了提示音?首先,手机是数字装置,我们必须将声音或者说空气震动转化成数字。假如你捕获一个WAVE文件或者MP3文件,就会发现这些文件所做的其实仅仅是测量大量的点位,从而将音频表现成为一连串数字。你所做的无非是按照固定时间间隔进行音量采样,确定这一时刻的音量有多大。我们在光盘背面往往能看到以下字样:44.1千赫,16比特。这意味着在读取这张光盘时每秒钟要取样44100次音量大小,取样的精确度是一个16比特的数字。这就是人耳接收的模拟信号与数字信号之间的转换方式。

现在我们将声音转化成了数字,可以在有需要时播放出来。现在我们只需将这些数字储存起来就好——可是有个问题,我们还没发明出文件系统。在半导体与固态硬盘问世之前,我们会找一根玻璃管灌满汞——当时是二十世纪五十年代,没这么多环保讲究,而且横竖是美国政府出钱——在玻璃管一段放置播音器,另一端放置听筒,然后将两者连在一起,这就是水银管延迟线存储法。声波在水银当中传播的很慢,从这头到那头要间隔半秒钟。听筒一旦接收到声音就立刻传输回播放器那头再次播放,从而在玻璃管内部形成驻波。只要将波峰当成1,波谷当成0,就相当于以数字形式存储了音频信息。我们全都将数据存储当成理所当然,想不到还需要有人发明这东西。画面上是UNIVAC I计算机当年用过的延迟管存储器。这一大坨器件共有18根存储管,每根能存储120比特的信息。UNIVAC I一共搭配了十台这样的存储器。艾伦.图灵曾经提议用杜松子酒代替汞,不幸的是并没有史料表明他的实验是否成功。

显然这项技术无法大规模推广,因为汞不仅昂贵,而且有毒。我们必须设计一个更好的系统。于是有人想出一个好主意:我们可以将磁性微粒敷在胶带或者旋转的圆盘上,然后用电磁铁逆转它们的状态。如果一切顺利,下次我们读取的时候这些微粒依然会保持逆转状态。这就是磁带与机械硬盘的原理。我们非常擅长制造机械硬盘,屏幕上机械硬盘运作的演示图像是放慢五十倍之后的结果。每当我们在机械硬盘上写入读出数据的时候,实际发生的情况如下:有若干块金属圆碟,它们每分钟都要旋转15000次,圆碟上有上千万亿个磁性微粒,我们要让探头移动到与4号圆碟相对的某个特定位置,接触到圆碟上的某个特定点,然后告诉我们这一点存储着怎样的比特。这就是磁性存储的基本原则,0与1就这样写在了物理介质上。假如看一下最早的操作系统——例如CPM与第一版MS-DOS——的文件分配表,文件名后面跟着的就是文件在物理硬盘上的物理定位与文件占用的物理空间。从那以后我们又发明了符号链接、目录、文件夹等等。但是文件分配表却在说:“如果你想读取COMMAND.COM文件,就前往磁盘的这个位置,读取这么多个比特。”

在发明磁盘的同时,我们还发明了随机存取存储器(RAM)。存储器的基本构件是半导体——或者说魔法。半导体是一个电开关,假如你将集电极通电,什么都不会发生;不过假如你将基极通电,就会接通电路,使得电流能从集电极流向发射极。在这个过程当中还可以对电信号加以放大。后来有人想到,假如我们将发射极与基极连接起来,那么这个开关只要通电就会一直保持通电状态,一旦断电又会一直保持断电状态。这样的装置也可以用来表示1与零,完全用不着汞。接下来又有人想到我们可以利用这个装置来构建存储体,用八个半导体可以表达八比特信息。我们将这些半导体的集电极并联在一起,输入源信号,然后过一会儿回来再读取原本的八比特信息。问题在于为了存储信息必须保持通电状态,一旦断电信息就会被抹去。然后又有人想出一个好主意:我们可以发明一种断电时依然能记得自己是否处于联通状态的魔法半导体。别人都说这是痴心妄想,我们已经证明了这种装置不可能存在。再然后就有人发明了浮置栅极,这玩意能发动神奇的量子魔法。在座各位谁家有小孩子?你们有没有这样的经历:刚才小孩子还在吃糖,一转眼他就爬到厨房里吃胶水去了,而且厨房门还上了锁,照理说小孩根本进不去。但是就在你没看着他的时候,他突然进入了某种量子叠加态。等你再次观察他的时候,他就跑到了原本不可能存在的地方。这就是固态内存的原理。我们对许多电子施加量子魔法,让它们进入位置无法确定的量子状态,其中有些电子会卡在浮置栅极里面——我们不知道它们是怎么进去的,它们也不知道自己是怎么进去的,反正它们就是进去了。接下来我们可以读取浮置栅极的状态,确定里面究竟有没有电子。如果要抹去信息,就向半导体通入强大电流,再次发动量子魔法,然后浮置栅极里面的电子就被抹掉了。根据传统物理定律,浮置栅极这种东西根本不该存在。那么你觉得这样一个元件要花多少钱才能买到?在亚马逊网站上花三十美元就能买到640亿个。我们现在不仅非常擅长发明这种东西,而且甚至更擅长制造这种东西并且把价格压下来。每当你为手机添置一张记忆卡的时候,你实际上购买的都是数百亿个根据传统物理学不可能存在的量子隧道之门。我们正是利用这样的装置来存储猫咪照片与MP3文件。

作为开发者,我们手头有这么多魔法一样的技术可供使用。启动几百亿个量子魔法门的咒语是什么?File .Read("notify.wav")。这句咒语所代表的的一层层抽象体系赋予了我们触手可及的强大力量。我们输入这条指令,这条指令会读取一连串比特,将比特转化成数字波,将数字波转化成模拟波,将模拟波输入指甲盖大小的扬声器,然后就得到了一声短信提示音。我们掏出手机一看,“啊,一张猫咪照片,这不是莱诺么。”那么这张照片又是怎么来的?首先太阳发出光,光穿过几亿英里的虚空,照射在莱诺的小脸上,其中一部分被它的连反射了出去,具体来说是红色、橙色与白色的光。这些光穿过手机镜头,照在光检器上,然后光检器放出电流。光照越多则光检器放电越多。光检器无法区分颜色,只能区分强度。于是有一位Bryce Bayer发明了由细小彩色玻璃颗粒组成的网栅。通过衡量每一颗微粒接收到了多少光线以及临近微粒接收到的光线,就可以得知网栅上的每一格接收到了多少红黄蓝光。现在的手机镜头标配是12兆像素,也就意味着光检器上有1200万个网格,而光检器的尺寸同样不比指甲盖大多少。

我们用手机拍照之后,手机首先生成了一套比特地图,包括一张红色图,一张绿色图,一张蓝色图,合成在一起就是一张莱诺的彩色图。1200万像素,每个像素八比特,其中0代表完全黑暗,255代表完全明亮,那么一张单色图就是9600万比特。三张单色图结合成彩色图之后的大小在未经压缩的情况下则大约是32Mb。这个数字听上去不算大,但是数字技术最大的好处就是便于将信息发往世界各地,因此接下来我们要前往斯洛伐克首都布拉迪斯拉发。前往此地有两大原因。首先,从澳大利亚到斯洛伐克的手机漫游费非常高,1Mb的数据要收费3美元。换句话说,将莱诺的照片从澳大利亚发到斯洛伐克需要耗资96美元。我认为这笔钱很值得花,不过在座各位可能有人不同意。其次,布拉迪斯拉发的啤酒价格在全欧盟最低,一瓶当地啤酒1欧元或者说1.6美元。换句话说发送莱诺照片的费用相当于六十瓶啤酒。于是我们突然就有了缩小这张图片的动机。如果我们能将传输图片所需的数据量削减一半,那么看图时将会有许多啤酒可以喝。

所以我们要怎样才能将欧洲之旅的啤酒钱省出来?哦们用手机镜头捕捉图片的时候使用了红绿蓝三个通道,0代表完全黑暗,255代表极致的颜色。但这并不是手机唯一使用的色彩模式。这套模式对于数字摄像头很好用,但是在处理图像时我们还必须采用另一套系统。这套新系统同样也有三条通道,分别是Y、CB与CR。Y源自图像技术初期将亮度与时间挂钩的图表,CB与CR分别代表蓝色亮度与红色亮度。用这套系统来衡量莱诺照片上的每一个像素,我们要问的问题是:首先这个像素的亮度是多少,其次这个像素偏蓝还是偏黄,最后这个像素偏红还是偏绿。之所以要开发这套系统,是因为人类肉眼观察细节与色彩的方式。人眼非常擅长识别黑白色的细节,并不太擅长识别彩色的细节。所以我们可以将莱诺的照片按照红绿蓝三通道分解开来,然后就可以抛弃掉原色图当中75%的信息,因为我们横竖看不出来。在原色图当中我们根本分辨不出莱诺的胡须与爪子,全靠黑白通道来体现这些细节。因此只要压缩图片,我们就抛弃了20%到30%的原本信息。一般进行JPEG压缩时图片大小都会缩小到原来的四分之一。

接下来我们要将这张图片放大到极限,将莱诺分割成许多八乘八像素的小方块——请放心,采用这一算法时没有猫咪受到伤害。接下来我们要考虑如何采用数学配方重现这个方块。JPEG压缩标准的核心是离散余弦变换(DCT),具体来说就是所有能以频率表达的八乘八方块的组合。这就是我们要使用的数学配方。我听说澳大利亚人对待汉堡包的态度非常认真,所以我用澳洲的加料特大汉堡打个比方。我们要怎样压缩特大汉堡的配方并且依然能够得到汉堡?汉堡配方包括面包、奶酪、甜菜根、菠萝等等。我们假如将蛋黄酱省略掉怎么样?还能做出汉堡吗?省略掉番茄酱又如何?还能做出汉堡吗?芥末酱还要吗?生菜叶子呢?我们这是在调节压缩造成的损失,我们要决定我们乐意省略多少信息。要不然我们把甜菜根也省掉吧——不行吗?那么这就是我们的压缩门槛。低于这个门槛,做出来的东西就不是汉堡了。不过在门槛之上我们已经压缩掉了73%的数据。JPEG压缩当中的八乘八方块就是我们的配方。方块左上角的白格相当于汉堡里的牛肉饼,绝对不可或缺。右下角的方格则代表大概没那么重要的细微末节。我们要做的就是将方块里的调味料与配菜都去掉。经过分析,我们将方块转化成矩阵,每个方格搭配一个数值,从而确定为了让解压缩后的方块与压缩前尽量相似需要保留哪些方格。我们注意到,左上角方格的数值是53,这个数字的重要性相当于牛肉饼,必须保留。其他数字则逐渐缩小,位于右下角的数字基本上已经与汉堡包扯不上关系了,都是些柠檬水之类,因此全都是0。我们在读取这些数字时既不按照横行也不按照纵列,而是按照之字形顺序读取,这就是JPEG ZigZag算法。最重要的数字总是最先出现,因此我们可以在读取过程中决定到哪一步可以开始省略。我们还可以在折线上做标记,确定标记之后的数字全都是0。这就是JPEG压缩的原理:我们抛弃掉关于颜色的信息,因为人眼横竖看不出来;然后我们将剩下的部分切成小块并且算出重现这些小块的数学配方;再然后我们扔掉配方当中可有可无的部分,得到近似结果。假如我们将JPEG文件高强度压缩之后再放大,甚至能看到这些小方块之间的分界。在有些方块当中,除了色彩渐变之外我们抛弃了一切,因为这些方块当中只有一样配料当真要紧。

我们高度压缩了莱诺,不过它似乎不太介意,看上去依然很悠闲。我们为自己节省了许多带宽,留出了许多啤酒钱。但是网上交流要讲规矩,有人给你发了猫图,根据礼节要求你必须回一个LOL。你可能会想发文本有什么难的?我们将照片转化成数据,又将数据还原成照片;我们将音频转化成数据,又将数据转化成音频。那么文本到数据再到文本的转化能有多难?有些听众看起来已经觉得头疼了。谁能认出这段摩斯码?···———···?这是SOS。那么···——···呢?这是短信服务的缩写SMS。为了将文本转化成数字信息,信息的发送者与接受者必须约定一套编码系统。我们将文字转化成数字,对面的人必须知道我们的转化过程才能将数字转化回来。最早也是最成功的文本编码系统当然是摩斯码。摩斯码非常灵活,可以使用电报点划,也可以使用手电筒闪光。摩斯码的问题在于不够高效。1960年美国计算机专家发明了ASCII,既美国信息交换标准代码。ASCII在我们看来是天经地义的存在,很难想象人们一开始还要把这东西发明出来。深入研究之后就会发现发明人想出了不少相当聪明的主意。好比说有人要求你:“请将这些资料按字母排序。”听上去很容易,但是有经验的人总会问一句:“是否区分大小写?”更有经验的人还会问:“SQL Server有280种代码页,你想用哪种?”这就显出了ASCII的聪明之处。ASCII是七比特编码,从0到127。0到31是控制字符,例如返回字符与换行字符,前者让打字机的打印头从页面末端回到开端,后者让打印机将纸张下移一行。不知何故,Mac OS、Linux与Windows无法就哪个字符应该表示“另起一行”达成共识。总之如果你想按照字母顺序对ASCII文档进行排序,并且想要区分大小写,那么就按照七比特的数值排序;如果不想区分大小写,就忽略第六位比特。

这套系统对于读写英语的美国人很好用,因为发明这套系统的人的设计出发点就是英语。我大约在十岁那年从非洲搬回了英国,有一天我在286家用电脑上做作业,其中出现了英镑标志£。但是当我将家庭作业打印出来之后,英镑标志却变成了ú。这是我第一次意识到字符编码的存在。在二十世纪七十到九十年代,美国以外的编码人员想到:“既然美国人利用了0到127,那么我们就利用128到255好了。”在英国我们用这部分编码做这些事,在西欧他们用同一套编码干别的事。世界各地都存在不同的代码页,换句话说人们利用这些扩展的ASCII字符表达了不同的东西。代码页的问题在于我们无法在文件内部标明该用哪种代码页来解读,必须依靠事先约定。

谁知道Привет是啥意思?这是俄语里的“hello”。俄语西里尔字母表自然与西方字母表一点也不像。当初俄国制造计算机进行文字编码时,国际标准化组织提供了一套现成的编码体系。当时七比特ASCII如此普及,以至于很多设备都应付不了八比特,在传输时干脆会将第八位比特省略掉。有的电子邮件系统会除去附件文本里的一切第八位比特,有的网络协议也会省略掉第八位比特。有人用七比特系统编码了Привет,输出之后变成了?'XRUB。于是有些俄国科学家认为美国人体会不到俄语的精妙之处,他们有更好的主意。于是他们发明了八比特КОИ编码。他们没有按照西里尔字母进行排序,而是按照发音最接近西里尔字母的英文字母进行排序。这样当Привет被输入七位比特系统之后,输出的就是pRIWET。俄国人故意颠倒了大小写,以示源文本在传输过程当中遭到了扭曲。

接下来我们谈一下人们如何解决了这个问题,不过在此之间我先讲个历史小插曲。1987年,比利.乔尔在苏联的列宁格勒——今天的圣彼得堡——开了一场个人演唱会。演出录音以黑胶唱片与磁带格式在苏联发行,标题是《比利.乔尔的концерт》——концерт就是俄语当中的“音乐会”。后来有人将索尼音乐库整理进入计算机系统,看到唱片封面这个词实在念不出来,于是将就着拼写成了Kohuept。直到今天你在iTune上搜索Kohuept依然能搜出这张唱片,在Spotify与Google Play上也能查到。会出现这么拗口的译名全都是因为二十世纪八十年代的我们以为自己已经完全解决了文本编码的问题。就算当初的人们认识俄语字母,他们的键盘上也没有能输入这些字母的相应键位。

历史趣闻暂告一段落,接下来统一码联盟闪亮登场。这个组织立志要一劳永逸地解决代码页五花八门的问题。但是统一码联盟其实只将这个问题解决了一半。他们打算人类的一切字母表当中的每一个正在或者曾经得到使用的字符分配一个代码点。为了实现这一目标,他们在0到127的部分沿用了ASCII——待会我再解释这样做的妙处——然后他们想到,既然代码点的数量理论上是无限的,那就把所有字母表都放进去好了。于是英语、俄语希腊语乃至扑克牌花色都有了独特的代码点。更有甚者,如果你真想极度压缩一段信息并且将其发往世界另一边,也可以借助事先约定的代码点。U+1F408,谁知道这是什么?这是脸朝左的家猫表情,这就是极度压缩过后的莱诺。接下来统一码联盟表示,现在所有字母都可以用数字代表了,剩下的问题就是你们工程师的事了。假设我们用四个字节来表示一个英文字母,也就是用三十二比特。以A为例,在ASCII当中A是65,或者说00000000/00000000/00000000/01000001。然后有一位还记得C语言与C++语言的白胡子老人家就发话了:“小子,你这个文本文件有问题啊。好些软件都应付不了一串全是0的字节。”因为全是0的字节在C语言、C++语言以及受其影响的编程语言当中是处理字符串时的终止符。因此基于现代命令行系统的许多应用都应对不了带有八个0的文本文件。于是他们想了半天,想出一个好主意,也就是UTF-8编码。UTF-8文件与ASCII文件可以相互转换,因为每一份只用七比特的ASCII文件也都是完全有效的UTF-8文件。所以我们可以继续使用一切早已存在的文件。然后他们想到,既然我们现在有了曾经害得很多人犯错的八比特,那么不妨利用这个比特来指示字节属于UTF-8序列。假如字节以11开头,那就是多字节字符串的开端;假如以10开头,那就是连续字符。字节的其余部分则都是数值。这个体系很容易扩展:如果开头是11,那么多字节字符串就包含两个字节,如果开头是111就包含三个字节,1111意味着四个字节。理论上来说这个体系能支持八个字节的字符编码。这个存储能力足以容纳人类历史上一切真实与虚构的字母表,甚至未来人类与射手座外星人互通邮件时要用的、现在还没发明出来的字母表,剩余的空间还可以用来设计表情包,例如小猫、爱心、笑脸与蜜蜂什么的。

所有这些复杂技术的关键在于:我们这些软件开发人员不需要理解其中细节就能自如应用。几个月之前有一张非常精彩的xkcd漫画,作者写道:“我有一个应用与一个日历页面,我希望两者能在平板上分屏显示,但是OS系统不支持分屏。于是我决定搭建我自己的应用……然后我意识到还不如买两部手机并排粘在一块背板上更容易。这一天我在软件领域开悟了。”在最后一格画面里,有人质问主人公:“但是你从没学会编程啊?”主人公答道:“我学会了如何将我不理解的东西粘在一起。”我们所有人在构建软件应用时本质上来说就是干这个。如今世界上已经没有人想要使用由懂得寄存器与处理器的人们编写的软件了。或许在二十世纪八十年代人们还能用电烙铁攒一台电脑然后在上面运行自己编写的游戏,还能借此将朋友吸引到你家来,但是如今计算技术远比当年更加重要。我们理解的东西更少了,而我们能做到的事情却更多了。发明JPEG压缩与4G蜂巢网络的人们的最初本意不是为了方便你往火车上发猫图。他们只想解决问题,为其他人提供解决方案,好让其他人创造出更酷的东西。我们的各种设备与应用之所以在大多数时候都能正常发挥作用,是因为当初那些人们想出的解决方案在大多数时候真的非常有效,以至于我们将这些解决方案当成了理所应当之物。直到你的手机没了信号的时候,或许你才会停下来想一想这一切其实并不简单,习以为常的背后是远远更加庞大复杂的机制。

在接下来三天,你们将有机会彼此交谈,与发言人交谈,与赞助商交谈,与组织者交谈。所有人来到这里的原因都是因为想要构建很酷的东西。我们想要将自己理解或者不理解的东西粘在一起。我们想创造优秀的应用与出色的用户体验。NDC这样的会议之所以精彩就是因为提供了面对面的机会。我想给大家提供一个小窍门。有谁是第一次参加此类大会?有谁是第一次来悉尼参加NDC?我想向大家介绍一下 Eric Holscher的吃豆人法则,这是鼓励对话进行的方法。假设你在十点钟来到会场,肯定会很自然地认为九点钟就来了并且正在三五成群凑成小圈子聊天的人们都是彼此熟识的朋友,唯有你却是外人,以至于不好意思插嘴。直接插进小圈子里发言也让人觉得很不讲礼貌。假如你正在小圈子里讨论Angular、React或者渐进算法,其他人插不进来,请记住吃豆人的外形。小圈子不要合拢成环形,而是应该留一个缺口留给外人加入。一旦这个缺口被填上,我们就应该让出新的缺口。这点举手之劳可以极大地改善所有人的交流体验,帮助人们更加轻松地讨论自己与EntityFramework的战斗经历。

技术上的事情都说完了,请大家再次欣赏一下莱诺卖萌图吧。谢谢大家。

通宝推:领班军机,唐家山,四方城,史文恭,菜根谭,山高与水长,易水,葡萄,
全看分页树展 · 主题


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河