硬卧

我醒了,闹钟仍未响,窗外却已见鱼肚白。从帽子里掏出手机,才六点出头。

硬卧的床仿佛是量身定制的,不宽不窄,恰能容下一个我。我睡前戴上了连衣的帽子,将手机放在帽子里,既防止手机从上铺跌落,也不怕错过了闹钟——现在看来是多余了。我小心翼翼地侧过身,对面的人还在熟睡。

应该快到站了。十三个小时前的傍晚,我才乘高铁来到上海,来看一场期待已久的演唱会。十三个小时后的清晨,我又乘着绿皮车,离开上海回到这里。计划本就是如此,无意多作停留。

阅读更多

Go Fact: Zero-sized Field at the Rear of a Struct Has Non-zero Size

There’s a concept in Golang called zero-sized type (or ZST), namely, a type whose variables take up zero bit of memory. One of them is the famous struct{}. People often use map[string]struct{} to efficiently emulate a set structure. Others include zero-length arrays such as [0]int, albeit not very common, are adopted to enforce some properties of a customized type.

阅读更多

Display *big.Rat Losslessly and Smartly in Golang

Floating-point numbers, as we know, are notorious for losing precision when their values become too large or too small. They are also bad at representing decimals accurately, yielding confusions like 0.1 + 0.2 != 0.3 for every beginner in their programming 101.

Albeit being imprecise, floats are good enough for most daily scenarios. For those not, however, Golang provides *big.Rat to the rescue. Rats are designed to represent rational numbers with arbitary precision, addressing most flaws of floats, yet at a cost of much slower computation speed and bigger memory footprint. For example, we are confident to compare 0.1 + 0.2 to 0.3 using Rats without caring about tolerance:

阅读更多

代码的仪式

我们常能在英文社区看到 coding ceremory 一词,或译为 代码的仪式。Stack Overflow 上有个问题 What does “low ceremony” mean?,作者曾如此提问:

In the Trac Main Features page https://trac.edgewall.org/wiki/TracFeatures, Trac is said to emphasize “ease of use and low ceremony”. Can someone please explain what “ceremony” means in the context of software usage?

low ceremony 与 ease of use 作并列短语,可见在程序开发的语境下,代码的仪式不是一个褒义词——过多的仪式并没有好处。用户 Rowan Freeman 则作此回答:

Low ceremony means a small amount of code to achieve something. It means you don’t need to set up a lot of things in order to get going.

如其所述,代码的仪式是完成一个功能所需要的额外准备。仪式越少,准备工作越简洁,完成起来也越容易。

代码仪式被称为仪式,正如古代祭祀的舞蹈,传统庆典的繁文缛节,其对完成目标贡献甚微,却又是不可或缺的步骤。复杂的仪式冗长而乏味,我们偏偏还得忍受其枯燥,如履薄冰,完成得分毫不差——这也解释了为什么大多数人都不喜欢代码仪式。

不同的代码仪式

依照呈现的形式,代码的仪式可以分为 编写仪式 和 运行仪式 两类。

阅读更多

阅读更多

中式亲属称谓研究之一:构建半群

前段时间在 V2EX 的一个帖子 /t/943948 中看到了一个有趣的问题:

在中文的亲属称谓体系中,我们会有“爸爸的爷爷”与“爷爷的爸爸”是同一个人,即“爸爸”和“爷爷”这两个称谓是可交换的。那么是否可以找到一个准则,以归纳所有这样的可交换称谓对?

欲解决这个问题,我们可以先使用群论对亲属关系进行建模,在此基础上分析其代数结构,进而得出亲属关系可交换的条件。本系列期用两篇博文阐述这一理论。此为其第一篇,将介绍亲属半群的建立以及该代数结构的相关性质。

阅读更多

Some Notes on Kotlin Coroutines

This post is written to dictate some opinionated explanation that dispels my confusion to Kotlin coroutines during learning.

阅读更多

Git sparse-checkout and partial clones for Mega-Repos

Recently I was planning to make a small contribution to project DefinitelyTyped/DefinitelyTyped. It is a huge repository that hosts and provides the type declaration files for thousands of packages on npm, with a structure like the following

types/
├── 11ty__eleventy-img
├── 1line-aa
├── 3box
├── ...and more of them...

Each sub-folder under the types/ directory corresponds to a specific npm package.

The package I am interested in is marked, whose type declaration files reside in types/marked/ directory. Towards this end, cloning the whole repository and doing a full checkout is considered worthless, since my disk space and network traffic would be eaten up by a bunch of irrelevant files.

阅读更多

辩义“封建”

“封建”一词很有意思。作为一个土生土长的中国词,它于千年前便有了固定而确切的含义。然而在近代西方思潮的冲击下,这个词的意义先是遭到了替换,而后又在近百年的传播中演化成了与本义毫不相干的概念。如今的人们谈及封建一词时,心中不免会有困惑,因为其现代含义与汉字构成相去甚远。更糟糕的是,在一些语境下,这个词会回归至其近代甚至是古代的含义,从而对相关的交流造成混乱。同一词的释义在多种语境下不一致,无谓的争吵便在所难免。

粗略地说,“封建”至少有四种释义,即古代中国的封建制度、古代欧洲的 Feudalism、近现代中国与 Feudalism 的对译,以及当代民间语境中的封建。

阅读更多

Diving from the CUDA Error 804 into a bug of libnvidia-container

Several users reported to encounter "Error 804: forward compatibility was attempted on non supported HW" during the usage of some customized PyTorch docker images on our GPU cluster.

At first glance I recognized the culprit to be a version mismatch between installed driver on the host and required driver in the image. The corrupted images as they described were built targeting CUDA == 11.3 with a corresponding driver version == 465 , while some of our hosts are shipped with driver version 460. As a solution I told them to downgrade the targeting CUDA version by choosing a base image such as nvidia/cuda:11.2.0-devel-ubuntu18.04, which indeed well solved the problem.

But later on I suspected the above hypothesis being the real cause. An observed counterexample was that another line of docker images targeting even higher CUDA version would run normally on those hosts, for example, the latest ghcr.io/pytorch/pytorch:2.0.0-devel built for CUDA == 11.7. This won’t be the case if CUDA version mismatch truly matters.

Afterwards I did a bit of research concerning the problem and learnt some interesting stuff which this post is going to share. In short, the recently released minor version compatibility allows applications built for newer CUDA to run on machines with some older drivers, but libnvidia-container doesn’t correcly handle it due to a bug and eventually leads to such an error.

Towards thorough comprehension, this post will first introduce the constitution of CUDA components, following with the compatibility policy of different components, and finally unravel the bug and devise a workaround for it. But before diving deep, I’ll give two Dockerfile samples to illustrate the problem.

阅读更多