2012-03-24 21 views
16

有人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)很難弄清楚。有人能解釋我是如何工作的嗎?有關此實現的任何參考?

+2

只是出於好奇:什麼是用於優化的用例? – user123444555621 2012-03-25 12:34:14

+0

驚人的速度!如果你打算(重新)寫一個當然的圖書館,這很有趣! – Redger 2012-03-25 12:54:31

+0

我永遠不會犧牲納秒性能增益的可讀性。 – user123444555621 2012-03-25 13:17:01

回答

13

year & 3year % 4相同。那裏不那麼棘手,它只是代表了通常的4年週期。

year & 15year % 16相同。

所以,這不是一個閏年,如果一年不被4整除,或者如果它不被16整除但由25整除這意味着,每25多不一個閏年,除非它也是16的倍數。由於16和25沒有任何共同的因素,唯一滿足這兩個條件的時間是年份是16 * 25或400年的倍數。 4 * 25的倍數將被認爲不是閏年,佔100年週期。

1900年不是閏年,因爲它可以被100整除,2000年閏年,因爲它可以被400整除,2100年不會是閏年。

+2

最佳答案! – Redger 2012-03-24 15:47:07

+0

另請參見http://stackoverflow.com/a/11595914/733805 – 2013-01-30 10:27:07

+0

您的詳細解釋導致我使用此算法到我的日常代碼中http://stackoverflow.com/questions/1810984/number-of-任天月/ 27946635#27946635(基本上我不會在解決方案中使用代碼,除非我完全理解它)。感謝和+1的偉大細節:) – 2015-01-16 15:28:53

5

如果一個數可以被16整除並且被25整除,那麼它可以被25(100)的四倍和25(400)的16倍整除。

+0

那麼如何通過400檢查整除? – Gareth 2012-03-24 15:24:25

+0

回答更新,因爲我必須確保我是對的:-) – Pointy 2012-03-24 15:27:31