万年历算法研究及实现

  • 格式:pdf
  • 大小:1.34 MB
  • 文档页数:2

下载文档原格式

  / 2
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

/*1752 年 9 月 3 日前的公式*/
else A = (D + 2*M + 3*(M+1)/5 + Y + Y/4 - Y/100
+ Y/400) % 7;
/*1752 年 9 月 3 日后的公式*/
printf("TODAY IS %s\n",name[f]);
}
参考文献 [1] 严蔚敏、吴伟民.数据结构.[M].北京:清华大学出版
十一月 0
十二月 275 2
十二月 2
十三月 306 5
十三月 5
十四月 337 1
十四月 1
表一
表二
在处理闰年 2 月 29 日的问题上,也有两种方法,第一:
把二月排在一年的最后,管他闰不闰,反正是最后一天,这
种算法设计的简洁、优美。第二:加了一个 if 分支,简单易
懂,直观有效,且效率并不差。
好了,该解决这个“历史遗留问题”了。其实,并没有
年的十三、十四月。采用查表的方法建表,并对 7 取模(表
一),再建立函数值表(表二),很显然二者是相同的。
三月 0 0
三月 0
四月 31 3
四月 3
五月 61 5
五月 5
六月 92 1
六月 1
七月 122 3
七月 3
八月 153 6
八月 6
九月 184 2
九月 2
十月 214 4
十月 4
十一月 245 0
M += 12;
Y--;
}
if ((Y < 1752)||((Y == 1752)&&(M < 9))||((Y ==
1752)&&(M == 9)&&(D < 3)))
/*判断是否在 1752 年 9 月 3 日前*/
A = (D + 2*M + 3*(M+1)/5 + Y + Y/4 +5) % 7;
24 25 26 27 28 29 30
有趣吧一个只有 19 天的九月。
那我们的算法也要跟着要大变身了。不用着急,我们分
析一下当前的情况:就是在原来的算法的基础上,出现了一
个比较特殊的 1752 年,我们的就针对这个特殊的地方进行
局部的调整,看看有什么可以办法解决这个问题。
不妨作如下演算:为了一致起见,采用一、二月作为上
++e; --y;
收稿日期:2007-3-20 作者简介:张剑锋 男(1981-) 研究方向:计算机科学技术
河南农业职业学院
教师
(451450)
144
Hale Waihona Puke Baidu
中国水运
第5卷
t=y+y/4-y/100+y/400+e;
f=t%7;
printf("TODAY IS %s\n",name[f]);
}
到此,似乎是问题基本都解决了。
我们再补上从当前 1 月 1 日开始到当前天的天数 e,即 为所求。
即 365*(y-1)+((y-1)/4-(y-1)/100+(y-1)/400)+e。 它的值即为当前天是从公元元年一月一日开始算起的第 几天。补上一个 x(x 是与公元元年一月一日是星期几有关的 一个 0~6 的整数),并将这个表达式赋给变量 t,即: t=x+365*(y-1)+((y-1)/4-(y-1)/100+(y-1)/400)+e,再用 t 除以 7,余几即为星期几(余 0 为星期日)。 下面讨论 x 的求法,如果知道公元元年一月一日是星期 几,就可以直接得到 x 的值,但现在公式还没有求出来,不 知道公元元年一月一日是星期几。不过没关系,毕竟知道最 近的日期是星期几。不妨看一下 2001 年 1 月 1 日是星期几, 结果是星期一,代入公式得 t=x+730516,用 730516 除以 7,得 104355,余数是 1,则为了保证 2001 年 1 月 1 日是 星期一,取 x 为 0,所以公元元年一月一日也是星期一。至 此,得到了完整的公式: t=365*(y-1)+((y-1)/4-(y-1)/100+(y-1)/400)+e, 再将它做一下改进,我们将公式变形为: t=(52*7+1)*(y-1)+((y-1)/4-(y-1)/100+(y-1)/400)+e, 利用星期的周期性,将 52*7+1 从公式中删除为: t=(y-1)+((y-1)/4-(y-1)/100+(y-1)/400)+e,
以下是这种算法的 C 语言程序: #include <stdio.h> char *name[]={"SUN","MON","THU","WED","THU","FRI","SA T"}; void main( ) {
int d,m,y,e,t,f; printf("INPUT THE DAY:"); scanf("%d",&d); printf("INPUT THE MONTH:"); scanf("%d",&m); printf("INPUT THE YEAR:"); scanf("%d",&y); switch(m) {
case 1:e=d;break; case 2:e=31+d;break; case 3:e=59+d;break; case 4:e=90+d;break; case 5:e=120+d;break; case 6:e=151+d;break; case 7:e=181+d;break; case 8:e=212+d;break; case 9:e=243+d;break; case 10:e=273+d;break; case 11:e=304+d;break; case 12:e=334+d;break; default:return; } if(y%4==0&&y%100!=0||y%400==0) if(m>2)
关键词:万年历 算法 阴历 阳历 闰年
中图分类号:TP29
文献标识码:A
文章编号:1006-7973(2007)04-0143-02
万年历是一个古老而又经典的算法问题,已经有不少的 实现方法,但是都多少会存在一些问题和不足,在这里对此 算法做一个系统的分析与介绍,先撇去农历与公历之间的转 化,只做公历与星期的讨论。
国人决定采用格利戈里历法,不过从 1582 年到那时,历法
又多出了 1 天,所以英国议会在 1752 年作出决定,抹掉 11
天—1752 年 9 月 3 日至 13 日。
这是怎么搞的,我们不是说过这样一个事实:从公元元
年一月一日开始到现在,每一天都是连续的,而每个星期有
七天,也是连续的,也就是说日期和星期是一对一的,没有
11 分 14 秒的误差已经累积成 10 天,也就是历法上多了 10
天。于是教皇格利戈里八世进行了一次校正。他在 1582 年
2 月 24 日以教皇训令颁布,将 1582 年 10 月 5 日至 14 日
抹掉,并且对原来的闰年方法进行了校正。经过校正的历法
叫格利戈里历法,也就是我们现在用的公历。1752 年,英
注意这样一个事实:从公元元年一月一日开始到现在, 每一天都是连续的,而每个星期有七天,也是连续的,也就 是说日期和星期是一对一的,没有断档现象。基本思想是: 计算出当前天是从公元元年一月一日开始的第几天,再利用 星期的周期性来计算公元任何一天是星期几。
假设当前年份为 y,并忽略闰年,则从公元元年一月一 日到 y-1 年共有 365*(y-1)天,加上闰年多出来的天数,即 加 上 1* ((y-1)/4-(y-1)/100+(y-1)/400) , 得 365*(y-1)+((y-1)/4-(y-1)/100+(y-1)/400)。
我们先不说这个算法本身,我们再来了解一下历法的知
识。
国际上使用的历法有几十种,其中最主要的有公历、回
历和佛历,即所谓三大历法。不管是哪种历法,无非是对年
月日的安排。这些安排主要依据天体的运动。
西方历法的第一次改革是罗马朱利乌斯·凯撒大帝引进
的。他采用的四年一闰的闰年方式。由于一个太阳年不刚好
是 365.25 天,而是 365.242199…天。到 16 世纪,每年
T"};
void main(){
int D,M,Y,A;
printf("Day: ");
scanf("%d",&D);
printf("Month: ");
scanf("%d",&M);
printf("Year: ");
scanf("%d",&Y);
if ((M == 1) || (M == 2))
{/*一月、二月当作前一年的十三、十四月*/
断档现象。现在居然又出现了特殊状况,我们以前的算法都
是错的。
不过一个简单的方法就可以证明确实存在着断档—用
Linux 的 cal 命令。启动你的 Linux 在#提示符下输入
cal 9 1752
你会看到:
September 1752
Su Mo Tu We Th Fr Sa
1 2 14 15 16
17 18 19 20 21 22 23
什么数学公式能算出指定日期是星期几,我们可以试着拼凑
一个,不过何必呢?加个 if 分支不就解决问题了吗?下面就
可得到突破 1752 年 9 月 14 日日期限制的 C 语言程序。
/*假设输入的是正确的日期*/
#include <stdio.h>
char
*name[]={"SUN","MON","THU","WED","THU","FRI","SA
第5卷 第4期 2007 年 4 月
中国水运 China Water Transport
万年历算法研究及实现
张剑锋 陈慕君
Vol.5 April
No.4 2007
摘 要:万年历是一个经典的算法问题,在教学过程中可以作为实例进行分析讲解,具有较高的学习分析价值,也
具有一定的实用价值,结合不同的方法,本文有一个系统全面的介绍。
社.1992. [2] 网冠科技.C 语言时尚编程百例.[M].北京:机械工业出
版社.2004.