17

JSPerf の誰かが、ISO カレンダーの閏年をチェックするための驚くほど高速な実装を落としました (リンク:奇数ビット操作):

function isLeapYear(year) {
  return !(year & 3 || year & 15 && !(year % 25));
}

Node.js を使用して、私が知っている他の 2 つのワンライナー実装と比較して簡単に確認しました。

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 の累乗 so(year % 4) == (year & 3)であることはわかっていyear & 15 && !(year % 25)ますが、把握するのは非常に困難です。誰かがそれがどのように機能するか説明できますか? この実装に関する参照はありますか?

4

2 に答える 2

14

year & 3と同じyear % 4です。それほどトリッキーではありませんが、通常の 4 年サイクルを表しています。

year & 15と同じyear % 16です。

したがって、その年が 4 で割り切れない場合、または 16 で割り切れないが 25 で割り切れる場合は、うるう年ではありません。 16 の倍数です。16 と 25 には公約数がないため、両方の条件が満たされるのは、年が 16*25 の倍数、つまり 400 年の場合だけです。4*25 の倍数は、100 年周期を考慮してうるう年ではないと見なされます。

1900 年は 100 で割り切れるので閏年ではなく、2000 年400 で割り切れるので閏年であり、2100 年はうるう年ではありません。

于 2012-03-24T15:40:36.610 に答える
5

ある数が 16 で割り切れ、25 で割り切れる場合、25 の 4 倍 (100) と 25 の 16 倍 (400) で割り切れます。

于 2012-03-24T15:21:43.027 に答える