萬年曆程式

一、幾月幾日星期幾

在探討萬年曆程式之前,我們先來看一下如果得知今年幾月幾日是星期幾,假設某月的 1 日是星期二,那麼 2 日就是星期三,而 N 日則是 (N-1+2) 再取七的餘數即可得知它是星期幾(星期天為 0)。我們再把這個公式再化簡,如果我們記錄該月第 1 日前一天的星期為 W,則該月第 N 日的星期則為 (N+W)%7 。如果我們可以先求出每個月的這個數字 W,將它放在陣列中,即可快速地求出每個月的任何一天是星期幾。以 2003 年為例,這一年十二個月的 W 值分別為 2、5、5、1、3、6、1、4、0、2、5、0,而這段程式可以寫成:

#include <stdio.h>

void main()

{

 int W[12]={2, 5, 5, 1, 3, 6, 1, 4, 0, 2, 5, 0};

 int m, d;

 scanf("%d %d",&m, &d);

 printf("%d\n", (W[m-1]+d)%7);

}

 

二、萬年曆程式

接下來我們希望這個程式可以輸入西元紀年、月份、日期,然後輸出它是星期幾。我們先列出 2002 到 2004 年每個月的 W 值:

年份

1

2

3

4

5

6

7

8

9

10

11

12

2002

1

4

4

0

2

5

0

3

6

1

4

6

2003

2

5

5

1

3

6

1

4

0

2

5

0

2004

3

6

0

3

5

1

3

6

2

4

0

2

從上表我們可以發現 2003 每個月的 W 值都是 2002 年的 W 值加上一,這是因為一年有 365 天, 365 除以 7 之後餘數為 1,因此每年同一天的星期會比上一年多 1。再看看 2004 年的部分,一、二月的還是 2003 年的加 1,但是三月以後的則是比 2003 年的多 2。這是因為 2004 是閏年,二月多了一天的緣故。從這邊我們可以得知,如果我們知道某一年的 W 值,即可以用年份及閏年的年數去求出當年的 W 值。閏年的規則為:

  1. 逢 4 年閏
  2. 逢 100 年不閏
  3. 逢 400 年閏

在這裡我們希望知道西元 0 年的 W 值,我們先用 2003 年的 W 值來計算,之後再用差值即可推出西元 0 年的 W 值。下面的程式我們用小寫的 w 代表該月份的 W 值,而大寫的 W 陣列則是西元 0 年的 W 值,程式如下:

#include <stdio.h>

void main()

{

 int W[12]={2, 5, 5, 1, 3, 6, 1, 4, 0, 2, 5, 0};

 int y, m, d, w;

 scanf("%d %d %d",&y, &m, &d);

 w=W[m-1]+y+(y/4)-(y/100)+(y/400);

 if( ((y%4)==0) && (m<3) ) {

   w--;

   if((y%100)==0) w++;

   if((y%400)==0) w--;

 }

 printf("%d\n", (w+d)%7);

}

上面黃色的那一段程式為判斷是否為閏年,如果是的話,三月以後的 W 值要加上 1。這段程式執行後輸入 2003 12 18,結果為 0,比真正的少 4,所以我們要改 W 值加上 4 才是正確的:

#include <stdio.h>

void main()

{

 int W[12]={6, 2, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};

 int y, m, d, w;

 scanf("%d %d %d",&y, &m, &d);

 w=W[m-1]+y+(y/4)-(y/100)+(y/400);

 if( ((y%4)==0) && (m<3) ) {

   w--;

   if((y%100)==0) w++;

   if((y%400)==0) w--;

 }

 printf("%d\n", (w+d)%7);

}

另外,因為我們用的西元紀年在 1582 年曾經改曆過,所以我們輸入的年份要在 1583 以後才有用,否則算出來的答案是錯的。下面我們列出幾個閏年及非閏年的日期,以印證我們的程式:

1911 10 10 -> 2

1892 3 3 -> 4

2000 1 1 -> 6

1900 6 18 -> 1

 

上一頁

首頁

下一頁