JSPerf上的某个人为了检查ISO日历的闰年而放弃了一个非常快的实现(链接:Odd bit manipulations):
function isLeapYear(year) {
return !(year & 3 || year & 15 && !(year % 25));
}
使用Node.js,我很快就与其他两个我认识的单线程实现进行了检查。
function isLeapClassic(y) { return (y % 4 == 0) && !(y % 100 == 0) || (y % 400 == 0); }
function isLeapXOR(y) { return (y % 4 == 0) ^ (y % 100 == 0) ^ (y % 400 == 0); }
function isLeapBitwise(y) { return !(y & 3 || y & 15 && !(y % 25)); }
//quick'n'dirty test on a small range!
//works with negative integers too
for (var i = 1900; i <= 2100; i++) {
console.log(
"year = %d,\t%d%d%d",
i,
isLeapClassic(i),
isLeapXOR(i),
isLeapBitwise(i)
);
}
它按预期工作,但我的问题是我无法弄清楚如何。
我知道((a % b) == (a & (b-1))
当b是2的幂时(year % 4) == (year & 3)
,但是year & 15 && !(year % 25)
很难弄明白。谁能解释一下它是如何工作的?有关此实现的任何参考?
答案 0 :(得分:14)
year & 3
与year % 4
相同。在那里并不那么棘手,它只代表了通常的4年周期。
year & 15
与year % 16
相同。
因此,如果年份不均匀地除以4,或者如果它不均匀地除以16但是均匀地除以25,则不闰年。这意味着每个倍数25岁不是闰年,除非它也是16的倍数。由于16和25没有任何共同因素,这两个条件的唯一时间是年份是16 * 25或400年的倍数。 4 * 25的倍数将被视为闰年,占100年周期。
1900年不是闰年,因为它可以被100整除,2000年 是闰年,因为它可以被400整除,2100年不会是闰年。答案 1 :(得分:5)
如果一个数字可被16整除并可被25整除,则它可以被整除4倍25(100)以及16倍25(400)。