中文和英文作为主流的两种语言,其实有不小的区别。可以比较的点很多,其中一种比较从信息论的角度用香农熵比较科学地给出了数学对比,即中文汉字比英文字母拥有更高的的香农熵,或者说信息容量,信息密度,因此表达同样的信息需要用到的中文字符更少。这比较符合人们的主观感受,比如同一本书的中文版往往比英文版更薄。
一个偶然的机会,我意识到可以从编写计算机程序的角度来做一个定量的比较,具体就是比较中英文数字的表达能力。
在之前的文章《ChatGPT-4
》里我让ChatGPT
自己给出“中文数字转换为阿拉伯数字
”的规则,要求它按规则写成程序代码,结果证明ChatGPT
无法完成任务。
规则看起来简单,小朋友就能懂,但写成代码并不容易,网上找了一些代码片段,质量参差不齐,就决定自己写。作为对比也找了一段英文数字转阿拉伯数字的代码一起作性能评估,比较算法速度
和内存开销
。
先上结果。
CN_To_Arabic
是我的代码,把“七千二百五十四万一千三百八十八
”转换为阿拉伯数字72541388
,没有额外的内存分配(Gen0
和Allocated
栏为空)。
英文数字转换是把英文数字”seventy-two million, five hundred and forty thousand, three hundred and eighty-eight
“转换为阿拉伯数字72541388
。英文存在大小写问题,比如”seventy-two million
“可能会写成”Seventy-two million
“。为了简化,也为了提高运行速度,我加了一些限定,只处理输入全部是小写字母的情况。
EN_To_Arabic_V1
是网上找的原始代码。花费时长是我的代码的8
倍多,外加960
个字节的托管堆内存分配,也就是会触发垃圾回收。代码首先把输入分割成一个个单词seventy
、two
等等并忽略分隔符
、逗号
和空格
,然后查字典得到对应的数字,比如seventy
对应到70
。这是很常见的写法,而分割字符串的操作会导致内存分配。
EN_To_Arabic_V2
是基于EN_To_Arabic_V1
的优化,利用最新的语言特性省掉了额外的内存分配,运行速度提高了47%
左右,但花费时长仍然是中文转换代码的4
倍多。
从测试结果看中文数字转换快得多,但这样的比较似乎并不公平——虽然表示的是相同的数字72541388
,但对应的中英文字符串长度有很大差别,所以英文转换慢也说得过去。
- 七千二百五十四万一千三百八十八(
15
个字符) - seventy-two million, five hundred and forty thousand, three hundred and eighty-eight(
84
个字符)
于是我用改进过的英文转换数字代码测试了几个短一点的英文数字作为对比:
108
:one hundred and eight(21
个字符)88
:eighty eight(12
个字符)1
:one(3
个字符)
测试结果显示字符少了之后转换英文数字确实快了不少(下图前三个测试),但实际上这是更加不公平的比赛。注意我们对比的是”把表示相同意义的数字转换为阿拉伯数字
“,不然的话转换108
、88
和1
对应中文数字的运行速度更是快得不成样子(后三个测试),无论如何中文数字转换速度都是碾压式的胜出。
同样可行的优化都被应用到中文和英文转换的代码中,我尽量做到客观不双标。算法也许还有优化的空间,但不变的事实是字符数量增多直接导致CPU
运算量增加,因此运行速度必然是字符少的胜出。表达同样的数字,英文需要的字符数比中文多得多,而且为了可读性需要引入连字符,逗号和空格,数字越大需要的字符越多
,因此从下图不难发现数字越大速度差别越大。
回到信息论方法,中文数字几乎可以做到与阿拉伯数字一一对应,有统计说单个字符信息容量是英文的2
倍多[参考资料1
]。还有上面的测试只针对”规范的中文数字
“,并不包含简化的情况。一般来说五位数以下的数字,中文表达中可以略去万
、千
、百
从而实现与阿拉伯数字一一对应。比如问身高多少厘米,回答一般是一七零
而不是一百七十
,还有程序员们熟悉的2
的乘方比如1024
,16384
,65536
等等。也正因为这种简洁表达,使得代码实现比英文高效得多——以”字符为单位
“的操作效率远高于以”字符串为单位
“的操作。
上述的程序代码的一次调用花费的时间在几十纳秒级别,1
纳秒是10
的负9
次方秒,几倍的效率提升看起来微不足道。但如果成千上万次甚至更多的并发调用积累起来产生的速度提升和内存开销降低对于改进用户体验、降低硬件成本就不再是可以忽略的因素。同理,阅读中文书和文章比阅读英文书和文章效率更高在某种程度上说是增加了一个人的可用时间。
文中的代码实现请移步github