【发布时间】:2010-06-28 21:40:08
【问题描述】:
我偶然发现了 Minix 的 gmtime 函数的源代码。我对从纪元以来的天数计算年份数的位感兴趣。这是那一点的胆量:
http://www.raspberryginger.com/jbailey/minix/html/gmtime_8c-source.html
http://www.raspberryginger.com/jbailey/minix/html/loc__time_8h-source.html
#define EPOCH_YR 1970
#define LEAPYEAR(year) (!((year) % 4) && (((year) % 100) || !((year) % 400)))
#define YEARSIZE(year) (LEAPYEAR(year) ? 366 : 365)
int year = EPOCH_YR;
while (dayno >= YEARSIZE(year)) {
dayno -= YEARSIZE(year);
year++;
}
看起来算法是 O(n),其中 n 是与 epoch 的距离。此外,LEAPYEAR 似乎必须为每一年单独计算——当前日期计算数十次,远期日期计算更多。我有以下算法来做同样的事情(在这种情况下来自 ISO-9601 时代(Year 0 = 1 BC)而不是 UNIX 时代):
#define CYCLE_1 365
#define CYCLE_4 (CYCLE_1 * 4 + 1)
#define CYCLE_100 (CYCLE_4 * 25 - 1)
#define CYCLE_400 (CYCLE_100 * 4 + 1)
year += 400 * (dayno / CYCLE_400)
dayno = dayno % CYCLE_400
year += 100 * (dayno / CYCLE_100)
dayno = dayno % CYCLE_100
year += 4 * (dayno / CYCLE_4)
dayno = dayno % CYCLE_4
year += 1 * (dayno / CYCLE_1)
dayno = dayno % CYCLE_1
这对于任何日期都在 O(1) 中运行,并且看起来即使对于相当接近 1970 年的日期它也应该更快。
那么,假设 Minix 开发人员是聪明人,他们这样做是有原因的,并且可能比我更了解 C,为什么?
【问题讨论】:
-
它看起来应该更快。您需要考虑您的架构以及某些指令(如乘法)的速度以及您拥有的分支预测器有多好(大多数都非常好)。 @jim mcnamara 有一些有趣的结果。