星期推算法

2021-04-06 17:59:28 字數 3622 閱讀 6191

通常我們只知道生活當天的前後幾天是星期幾,即便是翻日曆,也只能知道有限日期的星期數。那麼有沒有一種方法可以讓我們知道任何一天是星期幾呢?有,下面我將向大家介紹一種方法,用以編寫萬年曆的程式。

首先我們必須約定一些法則,我們用y、m、d分別表示年、月、日,用數字0-6分別表示星期日-星期六,這樣我們就可以開始推導我們的公式了。

我們知道2023年9月1號為星期日,如果我們要想知道2023年9月10號為星期幾,可以這樣算:(0+(10-1))%7=(0+9)%7=2,即星期二。同樣可算得2023年9月20號為:(0+(20-1))%7=(0+19)%7=5,即星期五。但是這樣算需要把日期減1,不太方便,為了解決這個問題,我們可以假設每個月有乙個0號,由於2023年9月1號為星期日,那麼2023年9月0號為星期六,這樣算9月10號,只需代入10既(6+10)%7=2。事實上,9月0號也就是8月31號,每個月0號的星期數實際上就是每個月1號的前一天的星期數。我把這個星期數稱之為每個月的**。有了這個**,要算這個月任一天的星期數都好辦了。

以上討論的是一年中每個月的**,事實上對於每年也有乙個**,這個**就是每年1月0號(即1月1號的前一天)的星期數,也就是一月份的**。如果我們能夠找到每年的**之間的關係,那麼要計算萬年曆就易如反掌了。

(一)推算年的**公式

我們都知道,平年一年有365天,即52週多1天。閏年為366天即52週多2天。我們先只考慮平年的情況。

假設第n年的**為w,則第n+1年的**為(w+1)%7,而第n+k年的**則為(w+k)%7。這是因為從第n年到第n+k年共經過了k年,每過一年也就是過了52周餘1天,經過k年也就是過了52*k周餘k天,將多餘的天數k加上第n年的**w再對7取模,所得也就是第n+k年的**了。

下面我們把閏年也考慮進來。判斷閏年的規則是,能被4整除,並能被100和400同時整除的年份就是閏年。所以從第n年到第n+k年間共有k/4 -k/100+k/400個閏年,而每個閏年有52周餘2天,要比平年多餘了1天,即共多餘了k/4-k/100+k/400天。我們應該把這些天也加進去,所以第n+k年的**應為(w+k+k/4-k/100+k/400)%7。

這樣子是不是就考慮完全了呢?並非如此,我們還有兩點沒考慮到。第一點是第n年是不是閏年。如果第n年是閏年的話,它本身就是52周餘2天,而我們在上面卻是把它當作平年來計算的,少算了1天,應加上。所以在第n年為閏年的時候上式應為(w+(k+1)+k/4-k/100+k/400)%7。第二點是第n+k年是不是閏年。如果第n+k年是閏年,雖然它有52周餘2天,但只有在算第n+(k+1)年的時候,才需要多加它那一天,而在算第n+k年的時候不需要多加這1天,因此我們必須將上式改為(w+(k+1)+(k-1)/4-(k-1)/100+(k-1)/400)%7(注意千萬不能改為(w+(k+1)+(k/4-k/100+k/400-1))%7=(w+k+k/4-k/100+k/400)%7)。

由此我們可以得出當第n年為閏年時,第n+k年的**計算式為:

a=(w+(k+1)+(k-1)/4-(k-1)/100+(k-1)/400)%7為了方便計算,我們可以取n為0,也就是假設公元元年的**為w。因為公元元年也是閏年,符合上式,那麼當我們輸入的年份為y時,此時就有k=y,也就是說第y年的**為

a=(w+(y+1)+(y-1)/4-(y-1)/100+(y-1)/400)%7接下來的問題就是w究竟是乙個什麼數了,下面我們就來解決這個問題。

我們已經知道2023年1月1號為星期二,它的前一天為星期一,那也就是說2023年的**就是1,由此我們可得

(w+(2002+1)+(2002-1)/4-(2002-1)/100+(2002-1)/400)%7=1

即(w+2488)%7=1

(w+3)%7=1

這樣我們就可求得w=5。我們的公式就變成了如下形式

a=(5+(y+1)+(y-1)/4-(y-1)/100+(y-1)/400)%7有了這個公式,我們就可以算公元後任意一年的**了,但還不能算西元前的,我們還需要再改進一下,得出公式(1):

(1)ayear= y>0 ? (5+(y+1)+(y-1)/4-(y-1)/100+(y-1)/400)%7

: (5 + y + y/4 - y/100 + y/400) % 7

這樣就ok了。不過這又導致了另乙個問題:y<0時,算得的a有可能小於0。這個問題我們暫且留下,待會再解決。

(二)推算月的**公式

年的問題解決了,月怎麼辦呢?請看下表:

月份**

差值一月a二月

a+3三月

a+3四月

a+6五月

a+1六月

a+4七月

a+6八月

a+2九月

a+5十月

a十一月

a+3十二月

a+5表中的a為當年的**。由這個表我們可以看出,月與月之間也有一定的關係。由此我們可以推出下面的公式(2):

(2)amonth=m>2 ? (ayear+2*(m+1)+3*(m+1)/5)%7

: (ayear+2*(m+2)+3*(m+2)/5)%7

但是上表所反映的僅為平年的情況,若y為閏年,則在m大於2時,每個月的**還需再加1。這可用乙個if語句解決:

(3)if (((y%4==0 && y%100!==0) || (y%400==0)) && m > 2)

amonth = (amonth+1)%7;

現在我們回到公式(1)中的問題。如果y<0時,使得ayear<0,那麼ayear最小也只能到-6。大家可以看到,當我們將ayear代入公式(2)時,問題就自然解決了。

(三)計算日期

有了上面的公式,當我們輸入日期後,就很容易算出當天為星期幾了,而且可以計算變數允許範圍內的任意一天的星期數。

(4)a = (amonth+d)%7

(四)寫程式

下面給出該萬年曆的程式,約莫估計,它可從西元前數十億年算到公元後數十億年(即從負十位數到正十位數),而且無一錯漏。

(程式中並沒有對輸入的月份和日期進行出錯處理)

#include

char *week = ;

void main()

int y;

int m;

int d;

int a;

printf("

enter year:");

scanf("%d",&y);

printf("

enter month:");

scanf("%d",&m);

printf("

enter date:");

scanf("%d",&d);

//下面的四條語句用來計算輸入日期的星期數,是程式的核心部分,缺一不可

a = y > 0 ? (5 + (y + 1) + (y - 1)/4 - (y - 1)/100 + (y - 1)/400) % 7

: (5 + y + y/4 - y/100 + y/400) % 7;

a = m > 2 ? (a + 2*(m + 1) + 3*(m + 1)/5) % 7

: (a + 2*(m + 2) + 3*(m + 2)/5) % 7;

if (((y%4 == 0 && y%100 != 0) || y%400 == 0) && m>2)

a = (a + 1) % 7;

a = (a + d) % 7;

printf("

i's a %s.

",week[a]);

}《轉貼》

遞推演算法二

b align center size medium 遞推演算法二 冪積數列 size align b size medium b 冪積數列 b m 輸入整數n,m求小於n的按從小到大的第m個元素 分析 list b 窮盡法 b 從2開始到n,如果n 2 0,n n 2一直迴圈的直到不能除盡 n 3...

遞推演算法(初學)

遞推演算法 乙個問題的求解需一系列 類似重複 的計算,在已知條件和所求問題之間總存在著某種相互聯絡的關係。通過已知條件,利用特定關係得出中間推論,直至得到結果的演算法。在解決問題的時候,去尋找前後過程之間的數學關係 即遞推式 遞推演算法避開了求項公式的麻煩,把乙個複雜的問題的求解,分解成了連續的若干...

遞推演算法(2)

有 2n 的乙個長方形方格,用乙個12 的骨牌鋪滿方格 編寫乙個程式,試對給出的任意乙個n n 0 輸出鋪法總數。演算法分析 1 當n 1時,只能是一種鋪法,鋪法總數有示為x1 1。2 當n 2時 骨牌可以兩個並列豎排,也可以並列橫排,再無其他方法,如下左圖所示,因此,鋪法總數表示為x2 2 3 當...