Google的新字体noto

最近我在VirtualBox上跑FreeBSD系统。安装好X窗口系统后,自带的中文字体非常丑陋,所以有必要安装一些新的字体。

根据我以往的经验,文泉驿提供了一套非常优质的中文字体,被许多Linux的发行版选作了默认的中文字体。在FreeBSD中也有wqy包可供安装。

文泉驿有一款字体称为微米黑,其基于Google的Droid Sans Fallback,通过部件拼接来构造汉字,从而在保持字体体积较小的情况下包含大量的字符。文泉驿制作微米黑是为了补充Droid Sans Fallback缺失的字符。

今天我查看Wikipedia页面的时候,看到Google发布了一款新的字体:Noto。其名称有一个来源:浏览网页时,字体中不包含的字符通常会被显示为豆腐块。而Noto的目标是消灭豆腐块(No more tofu)。这个字体从2014年开工,一年不到就已完工,整个字体的体积高达460MB,其中绝大部分(400MB以上)是CJK字体。CJK字体包含了简体、繁体、日文和朝鲜文4种变体,以迎合不同地区的习惯。

于是我卸载了文泉驿,改而安装Noto字体。

继续阅读 →

Python Quines

Quine指的是一种特殊的程序,其输出内容等于其自身代码。想写出这样的程序需要动一番脑筋。

如下代码即为Python的quine:

s='s=%s;print(s%%repr(s))';print(s%repr(s))
继续阅读 →

在Android中关闭开发者选项

在Android中点击5次“内部版本号”即可激活开发者选项,其中可以设置USB调试等功能。今天我发现了关闭开发者选项的方法,如StackExchange所述,只需清除“设置”应用程序的数据即可。 继续阅读 →

超轻量字符缓冲区库

在写yasf项目的过程中遇到这样的需求:为了构造SQL语句,我必须将若干个字符串拼接起来。一个凑合的办法是,定义一个足够大的静态缓冲区,然后使用诸如sprintf这样的库函数来构造字符串。但是事实上,构造出来的字符串的总长度是没有上限的。因此,若使用固定长度的缓冲区则会带来缓冲区溢出的隐患(C语言最著名的缺陷之一)。

大部分现代的语言的字符串功能都远强于C,字符串拼接更是非常基本的功能。选择C作为开发语言,那就不得不重复造轮子。我总抱着自己能造出更好的轮子的虚幻的指望。经过若干次试验,我得到了一种比较满意的实现方式。于是我把它从yasf项目中抽了出来,做成一个独立的模块,放在GitHub上,命名为ulbuf(__u__ltra __l__ightweight __buf__fer)。

整个实现的代码不足百行,功能也是少之又少。我发现,只有这样才能保证最大的灵活性。

整个库的特点:

简单

API非常简单,共4个函数。其中,2个用于缓冲区的创建和销毁,1个是为了便于使用而提供的便捷函数。因此,最关键的函数只有1个。

API的参数和返回值的形式是经过仔细设计的。

灵活

在C语言中,用户常常通过增/减指针来表示向字符串中增添/删除字符。只要预留了空间,ulbuf仍允许他们这样做。

在最初的实现中,ulbuf还保存了“缓冲区中已含有的字节数”这一个信息。并且只能向缓冲区中追加内容。对于yasf项目而言,已经足够。

现在的实现中,ulbuf只负责管理缓冲区的容量(最多能容纳的字节数),不储存已含有的字节数信息。既能简化实现,又能保证使用的灵活性。这可能是体现“少即是多”的一个例子。

鲁棒

当用户提示ulbuf需要向缓冲区中写入n个字符时,ulbuf会在第n+1个字符的位置写入字符'\0'。因此,缓冲区的内容永远是合法的C字符串。这样,使用C标准库操作缓冲区永远不会发生内存越界的错误。

协调

ulbuf创建的缓冲区是char *类型,可以把它当作正常的字符串,提供给诸如strlenstrchr这类标准库函数。

只要预留了空间,那么也可以把缓冲区作为输出参数,提供给诸如strcpysprintf这类函数使用也是完全没有问题的。这类函数会在第n+1个字符的位置添上一个字符'\0',仅仅是把ulbuf已经写入的'\0'覆写了一次,而没有发生内存越界访问。

高效

在我的平台上测试重复追加字符串的操作,ulbuf的运行速度略快于C++ STL的string类。

因为STL通常是仔细编写的、深度优化的运行库,可见ulbuf的运行效率是很高的。(欲知具体情况,可以编译并运行代码仓库中的example.cc程序。)

继续阅读 →

YASF的进度

yasf是我正在写的一个SQLite的图形前端。目前写好了大体的图形界面。能够读取SQLite数据库(而不能编辑)。

以下为未成品的截图。图中的对话框用于创建新的索引(仅仅是界面)。

继续阅读 →

扑克中的概率论问题

前天下午打牌,触景生情想起了一个概率论的问题:3个人打一副扑克(A23456789 10 JQK各4张+大小王=54张牌),随机发牌,每人拿18张。设随机变量X表示三个手中的炸弹(指4张点数相同的牌)的总数,求X的分布律。

这样的问题理论上应该可以使用古典概型来求解。但是我想了一会之后就放弃了。为了对这个问题有一个大概的了解,我写了一段程序模拟洗牌和发牌的过程并且统计其中的炸弹个数。

从程序的输出中我得到了一个有趣的结果。下面是某一百万次试验中得到的统计结果:

685121
259261
49135
5935
520
28
0

从上到下依次是X=0,1,2……的频数。6个炸弹以上的情况没有出现。

下面是条形统计图,可见,随着炸弹数增加,频数迅速减小。概率最大的事件是没有炸弹。炸弹个数不超过1个的频率高达94%,这和我平时打牌的常识相符合。

继续阅读 →

基于Docker的自动构建

Wercker现在支持基于Docker的自动部署。我不是很清楚Docker的运作原理。就我现在的理解,Docker是一个虚拟机快照,其中已经配置好了用户所需要的软件。每次运行时,就是解包这个虚拟机然后执行任务。

之前因为ArjenSchwarz/wercker-step-hugo-build这个脚本不支持基于Docker的自动构建,所以我还在使用Wercker的旧的构建模式。

问题在于,在目前基于Docker的构建模式中,默认的虚拟机debian只是一个空壳,像git和wget这样的软件统统都没有安装。

在构建的时候,脚本需要使用wget下载hugo程序。我曾试过在构建之前执行

apt-get -y install wget

但是似乎找不到这个软件包。今天我发现构建脚本更新了,不知道作者是不是也遇到了同样的问题,所以改而使用curl。

我还需要安装git。这个过程会下载很多软件包并安装。构建的时候做一次,部署的时候又做一次,浪费时间和计算资源,我觉得很不合理。

我觉得合理的做法是,在Docker的虚拟机中预先安装好git和hugo,这样每次构建的时候只需解包虚拟机并且运行就可以了,并不需要安装额外的软件包。只是我现在还不知道怎样实现这样的Docker功能。

目前最好的结果是,我找到了yesops/git这个Docker,其中已经安装好了git和curl。这样我就不用再去劳烦apt-get了,应该可以省去不少重复劳动,虽然不是人力劳动而是自动化的机器劳动。

继续阅读 →

抛硬币问题的另解

周四将要进行《概率论与数理统计》的期末考试。为了表示纪念,研究一个和概率论相关的问题。

连续抛掷一枚硬币,直到出现连续的两个正面为止。问:抛掷次数的数学期望是多少?

继续阅读 →

负反馈放大电路

明天将要进行《模拟电子线路》课程的期末考试。今日特地记一道题目以作纪念。

问题是这样的:反馈放大电路如图所示。请

  1. 判断反馈的组态;
  2. 估算闭环增益\(A_f\)。

已知:\(R_s\)的值已经很高,可以略去。

继续阅读 →