7-27 计算天数及星期值
7-27 计算天数及星期值
题目描述:
你知道你生日那天是星期几吗,你知道你爸爸生日那天是星期几吗?你可能会说:可以查万年历啊。然而,不查万年历你能计算出来吗?编程序实现:输入任意一个日期的年、月、日的值,求出从公元1年1月1日到该日期前一年的年末总共有多少天,到该日期前一个月的月末总共有多少天,到这一天总共有多少天,并求出这一天是星期几(用英文表示)。假定从公元第一天开始,就实施格里高利历法,并且公元1年1月1日为星期一。格里高利历法的置闰规则是400年97闰,也可以概括为:四闰百不闰,四百闰。提示:可以将每个月的天数存入一个数组中。
输入格式:
输入年、月、日的值,数据之间以空格分隔。
输出格式:
数据之间以换行符分隔。
输入样例:
2012 3 31
输出样例:
734502
734562
734593
Saturday
原代码:
#include<stdio.h>
int main ()
{
int a[12]={
31,28,31,30,31,30,31,31,30,31,30,31};
char b[7][10]={
"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
int n,y,r,i,s1=0,s2=0,s3=0;
scanf("%d %d %d",&n,&y,&r);
for(i=1;i<n;i++)
if((i%4==0&&i%100!=0)||i%400==0) s1+=366;
else s1+=365;
if((n%4==0&&n%100!=0)||n%400==0) a[1]=29;
s2=s1;
for(i=0;i<y-1;i++)
s2+=a[i];
s3=s2+r;
printf("%d\n%d\n%d\n%s\n",s1,s2,s3,b[s3%7]);
}
总结:
1、该代码是通过求出总天数再对7求余实现求算星期几的,余数只会是0,1,2,3,4,5,6,所以数组b的元素顺序应为"Sunday",“Monday”,“Tuesday”,“Wednesday”,“Thursday”,“Friday”,“Saturday”。
2、非常重要的一点:月份对应的下标为(月份数-1),所以“计算公元1年1月1日到该日期前一个月的月末的天数”的for循环的控制条件为(>=0&&<该月-1),1月份下标为0,2月份下标为1。
微调1(基姆拉尔森公式求星期几):
基姆拉尔森计算公式:W= (d+2m+3(m+1)/5+y+y/4-y/100+y/400+1)%7
#include<stdio.h>
int main ()
{
int a[12]={
31,28,31,30,31,30,31,31,30,31,30,31};
char b[7][10]={
"Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"};
int n,y,r,i,s1=0,s2=0,s3=0;
scanf("%d %d %d",&n,&y,&r);
for(i=1;i<n;i++)
if((i%4==0&&i%100!=0)||i%400==0) s1+=366;
else s1+=365;
if((n%4==0&&n%100!=0)||n%400==0) a[1]=29;
s2=s1;
for(i=0;i<y-1;i++)
s2+=a[i];
s3=s2+r;
int w=(r+2*y+3*(y+1)/5+n+n/4-n/100+n/400)%7;
printf("%d\n%d\n%d\n%s\n",s1,s2,s3,b[w]);
}
与原代码的区别:
因为基姆拉尔森计算式直接求出的就是星期几,所以w的取值只可能是1~7,分别对应"Monday",“Tuesday”,“Wednesday”,“Thursday”,“Friday”,“Saturday”,“Sunday”。
所以数组b的元素位置要进行调换。
微调2:
#include<stdio.h>
int main ()
{
int a[13]={
0,31,28,31,30,31,30,31,31,30,31,30,31};
char b[7][10]={
"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
int n,y,r,i,s1=0,s2=0,s3=0;
scanf("%d %d %d",&n,&y,&r);
for(i=1;i<n;i++)
if((i%4==0&&i%100!=0)||i%400==0) s1+=366;
else s1+=365;
if((n%4==0&&n%100!=0)||n%400==0) a[2]=29;
s2=s1;
for(i=1;i<y;i++)
s2+=a[i];
s3=s2+r;
printf("%d\n%d\n%d\n%s\n",s1,s2,s3,b[s3%7]);
}
与原代码的区别:
储存月份天数的数组月份对应下标的改变,使月份数等于下标。
看似只需改动一处,实则还改变了“计算公元1年1月1日到该日期前一个月的月末的天数”的for循环的控制条件,由于当月的天数不用计算在内,故范围为(>=1&&<该月)。同时计算二月份对应数组位置变为a[2]。
微调3:
#include<stdio.h>
int main ()
{
int a[12]={
31,28,31,30,31,30,31,31,30,31,30,31};
char b[7][10]={
"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
int n,y,r,i,s1=0,s2=0,s3=0,temp,j;
scanf("%d %d %d",&n,&y,&r);
for(i=1;i<n;i++)
{
temp=0;
if((i%4==0&&i%100!=0)||i%400==0) a[1]=29;
else a[1]=28;
for(j=0;j<12;j++)
temp+=a[j];
s1+=temp;
}
if((n%4==0&&n%100!=0)||n%400==0) a[1]=29;
else a[1]=28;
s2=s1;
for(i=0;i<y-1;i++)
s2+=a[i];
s3=s2+r;
printf("%d\n%d\n%d\n%s\n",s1,s2,s3,b[s3%7]);
}
与原代码的区别:
改变了“从公元1年1月1日到该日期前一年的年末的天数”的计算方式。
采用for循环,利用临时变量存储每一年的天数,再加到总天数里。由于每次循环后2月份的天数a[1]都会发生改变,所以不只要有if,也要有else,即
if((n%4==0&&n%100!=0)||n%400==0) a[1]=29;
else a[1]=28;
又因为计算“从公元1年1月1日到该日期前一年的年末的天数”的for循环结束后,a[1]的并不确定,所以在进行“计算公元1年1月1日到该日期前一个月的月末的天数”时也要有else,即
if((n%4==0&&n%100!=0)||n%400==0) a[1]=29;
else a[1]=28;
微调4:
#include<stdio.h>
int main ()
{
int a[12]={
31,28,31,30,31,30,31,31,30,31,30,31};
char b[7][10]={
"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
int n,y,r,i,s1=0,s2=0,s3=0;
scanf("%d %d %d",&n,&y,&r);
s1=(n-1)*365+(n-1)/4-(n-1)/100+(n-1)/400;//每一年都当成365天,再加上闰年的个数,由于当年不计算在内,故总年数为n-1
if((n%4==0&&n%100!=0)||n%400==0) a[1]=29;
s2=s1;
for(i=0;i<y-1;i++)
s2+=a[i];
s3=s2+r;
printf("%d\n%d\n%d\n%s\n",s1,s2,s3,b[s3%7]);
}