你是否曾经想过条形码是如何工作的?条形码的正式名称是EAN-13(E本来代表欧洲,但现在在世界范围内都通用),由13个数字组成。每个国家都有一个或多个前缀,如意大利、圣马力诺和梵蒂冈的前缀是800~839。在这几个国家,不同的公司会根据这几个数字进行编码来区分管理自己的产品。

从技术的角度来看,每个代码数字对应着不同宽度的黑条与白条的特定组合。事实上,这些不是我们平时所看到的数字,而是被二进制数所代替了。1代表一个黑条,0表示一个空白。如果一个黑条或一个空白很宽,则意味着有更多相同的连续二进制数。另外,还有三组控制线,两组在两端,一组在中心,使得扫描枪能对齐条形码,准确地读取数字。条形码分为两个包含6个数字的组:第2 ~ 7位有两种可能的编码,而第8~13位有一个唯一的编码,它正是前两个编码其中一个的回文,这样的话既可以从左往右读取条形码,也可以从右往左读取条形码。

那么大家也许会问了 :那第一位上的数字是怎么编码的呢?很聪明的问题。对于第一个数字,没有采用编码,这是一个元数据。这多多少少有点像隐写术,也就是说,巧妙地在一条信息里隐藏另外一条信息。对于第一组的数字,使用这个或那个编码是通过第一个字符所代表的条形码依次进行选择的。

但是,即使扫描枪读码非常准确,也会有读取错误的可能。不小心把花生装进香槟箱子里,然后客人给的还是香槟的钱,这样不是很好吗?这种情况下,你能做些什么呢?很简单:第13位数字是其他12位唯一定义的校验码。这意味着,在读取条形码的各个数字时,也会执行一些校验操作—就像在用试金石一样,如果最终结果跟预期的结果不一样,那么就意味着出现了问题。

在EAN码家族中,即使有13位以外的数字,这些操作也很简单。在编码过程中,最右边的数字会被去掉—即便它是负责校验的数字,我们照样不认账!然后把数字从右到左按数位交替乘以3和1,再进行相加。只取最终结果的最后一个数字—这显然是0~9之间的数字;然后用10减去这个数字,得到的结果就是EAN码的第13位数字;如果结果是10的话,那么第13位数字就为0。为什么我们可以运用这个算法?首先,大家可以看到,这种方法可以很容易检测到任何一位数字上的错误。并且,如果有两个数字不小心调换了,也几乎总是能发现。唯一没办法检测出的是当这两个数字刚好相差5的时候,因为乘1或乘3相差的刚好是2,而2乘以5刚好等于10。这里就不去管为什么是乘以1或3而不是1或2了,但肯定是有原因的。不要跑来跟我说什么“谁会在乎一个条形码中间有两位数字被调换了?”

显然,你们是没有买到那种条形码是售货员手写的,没办法读取出来的产品。

我们能通过校验码把条形码设计得更好吗?没错。这里有一个例子是十年前十位数的ISBN代码,不是现在的ISBN代码,那时它的地位跟现在的EAN代码是一的,区别在于对后者来说多了一个虚构的国家代码—“书城”(bookland),在其他代码前加上了前缀978;此外,校验码的计算方法也是不同的。确切地说,在旧的ISBN代码中,将不同位置上的数字分别乘以1,2,3,…,10,最后的和必须是11的倍数。但是是从右到左还是反过来呢?好吧,这无关紧要。既然我们对除以11后的余数感兴趣,那么我们就采用模块式算术 :我们假设时钟上有11个小时,不是12个小时,然后让这些数字向前或向后移动一格。如果我们把两个指针方向相反的数字相加,那么得到的结果将会是0的镜像—由于0与其本身是相反的,所以没有任何问题。

由于11是一个质数,这可以证明在两个ISBN-10书号中,不可能存在8位数字匹配而另2位数字是互换的情况。从更广泛的角度上来说,所有有效的条形码相互之间至少有2个数字是不同的。因此,以EAN码为例,如果一个条形码中只有1个数字是错误的,那么这个条形码肯定是无效的。唯一的问题是,这个校验位有11种不同的可能性,而我们只有10个数字。这就是为什么我们有时会看到字母X,它代表的就是数字10。

来源: 《午餐时间聊数学》