基姆拉爾森公式

2022-01-10 00:16:15 字數 3752 閱讀 7111

基姆拉爾森公式 (kim larsen calculation formula) 用於給定年份 \(y\) , 月份 \(m\) 和日子 \(d\) 的條件下,計算該天是星期幾。

初始條件:從公元 0 年 1 月 1 日,星期日開始計算(ps:公元 0 年不是閏年)。

輸入: \(y, m, d\) 三個整數表示年月日。

輸出:\(w \in [0, 6]\) 分別表示星期日到星期六。

下面為推導過程。

對於公元 0 年的第乙個月:

\[w = (d-1) \mod 7

\]考慮公元 0 年後的年份,不考慮閏年(即假設每年均為 365 天),因為365 % 7 == 1,所以公元 1 年第一天是星期一,公元 2 年第二天是星期二,以此類推。在不考慮閏年的情況下,對於公元 \(y\) 年的 1 月:

\[w = (d-1+y) \mod 7

\]考慮閏年,在 \([0,y-1]\) 區間內假設有 \(k\) 個閏年,那麼公元 \(y\) 年第乙個月的 \(w\) 需要加上 \(k\) 進行修正。

閏年的條件是:整除 400 或者整除 100 但不能整除 4 。所以 \(k = (y-1)/400 + ((y-1)/4 - (y-1)/100)\) ,其中/表示 c 語言的整型除法。

所以,在考慮閏年的情況下,公元 \(y\) 年的1 月的星期幾:

\[w = [d-1 + y + (y-1)/400 + ((y-1)/4 - (y-1)/100)] \mod 7

\]接下來,將上述公式推廣到公元 \(y\) 年的任意月份。

公元 \(y\) 年的第 29 天的 \(w\) 值總是與第一天相同的。以 28 為基準,某些月份會多出幾天的偏移,比如日期0/1/1是星期日,w = 0,1 月的偏移為 3 ,所以 日期0/2/1是星期三,w = 3

現在我們需要找出每個月份基於 1 月的偏移量(暫不考慮閏年)。

月份累計偏移

該月偏移

累計偏移模 710

3023

0333

3346

2658

31611

24713

36816

32919

25102130

112423

122635

以陣列記錄**的第 4 列:disp =.

所以,不考慮考慮閏年的情況下,對於任意的 \(m\) 有:

\[w = \ \mod 7

\]如果考慮閏年,那麼 2 月之後的月份的 \(w\) 值都需要加 1 處理。

**表示即為:

#define isleap(y) (((y) % 400 == 0) || (((y) % 4 == 0) && ((y) % 100 != 0)))

int week(int y, int m, int d)

; int w = ((d - 1) + y + ((y - 1) / 400 + (y - 1) / 4 - (y - 1) / 100) + disp[m]) % 7;

if (m > 2 && y != 0 && isleap(y))

w = (w + 1) % 7;

return w;

}

下面考慮如何優化,因為disp陣列每次使用都要手動算一遍。當然,下面很多技巧都是根據已有的結果反推過程而已。

假設把n年的 1 月和 2 月「劃分」到n-1年,作為n-1年的第 13 月和 14 月。而每年的第一天是 3 月 1 日,即每年的月份範圍是 \([3, 14]\) .

公元 0 年 3 月 1 日是星期三,所以對於公元 0 年 3 月有:

\[w = (d+2) \mod 7

\]考慮閏年,對於公元 \(y\) 年的 3 月,這時候需要考慮的是 \([0,y]\) 範圍內的閏年個數,/表示 c 語言整型除法:

\[w = [d+2+y+(y/400+y/4-y/100)] \mod 7

\]偏移量**:

月份累計偏移

該月偏移

累計偏移模730

3043

2355

3568

21710

33813

36916

22101834

112120

122332

132635

142901

暫時引入disp[m] (3 <= m <= 14)記錄累計偏移模 7 .

考慮閏年,推廣到任意月份 \(m\) :

\[w = \ \mod 7 \quad (3 \le m \le 14)

\]這時候 2 月是該年的最後乙個月,不需要考慮上述「如果考慮閏年,那麼 2 月之後的月份的 \(w\) 值都需要加 1 處理」的情況。

站在巨人的肩膀上,可以發現(/表示整型除法):

\[disp[m] = (2m+3(m+1)/5-1) \mod 7, \quad (3 \le m \le 14)

\]所以:

\[w = [d + y + 1 + (2m+3(m+1)/5) + (y/400+y/4-y/100)] \mod 7 \quad (3 \le m \le 14)

\]

int calcdayofweek(int y, int m, int d)

完整帶測試**:

#include #include #include #include #define isleap(y) (((y) % 400 == 0) || (((y) % 4 == 0) && ((y) % 100 != 0)))

#define yearlim (10000)

using namespace std;

int week(int y, int m, int d)

; int w = ((d - 1) + y + ((y - 1) / 400 + (y - 1) / 4 - (y - 1) / 100) + disp[m]) % 7;

if (m > 2 && y != 0 && isleap(y))

w = (w + 1) % 7;

return w;

}int calcdayofweek(int y, int m, int d)

const char *format = "%4d/%02d/%02d\n";

void test(int y, int m, int d)

int main()

cout << "-------------------" << endl;

// leap years test

for (int i = 0; i < 1000; i++)

// feb. test

cout << "-------------------" << endl;

for (int i = 0; i < 1000; i++)

// 29,feb test

cout << "-------------------" << endl;

for (int i = 0; i < 1000; i++)

}

基姆拉爾森計算公式

功能描述 根據輸入的日期判斷當天是週幾 演算法如下 基姆拉爾森計算公式 w d 2 m 3 m 1 5 y y 4 y 100 y 400 mod 7 在公式中d表示日期中的日數,m表示月份數,y表示年數。注意 在公式中有個與其他公式不同的地方 判斷日期是該月的第幾周 datetime.now.da...

基姆拉爾森公式 判斷星期幾

時間限制 2000 ms 記憶體限制 65535 kb 難度 2 描述 acm的iphxer經常忘記某天是星期幾,但是他記那天的具體日期,他希望你能寫個程式幫幫他。輸入 每行有三個整數 year,month,day,日期在1600年1月1日到9600年1月1日之間 輸出輸出對應的星期,用乙個整數表示...

基姆拉爾森計算公式 推導

給定乙個 x xx xx日期,計算為星期幾。int y 年 int m 月 int d 日 int w 週幾從 公元0年1月1日星期日 開始 w d 1 7 公式 1 w d 1 y 7 公式 2 y 4 y 100 y 400結合之前的公式1,2 w d 1 y y 1 4 y 1 100 y 1...