一个计算万年历的简单程序

作  者:李  庚

通常我们只知道生活当天的前后几天是星期几,即便是翻日历,也只能知道有限日期的星期数。那么有没有一种方法可以让我们知道任何一天是星期几呢?有,下面我将向大家介绍一种方法,用以编写万年历的程序。

首先我们必须约定一些法则,我们用Y、M、D分别表示年、月、日,用数字0-6分别表示星期日-星期六,这样我们就可以开始推导我们的公式了。

我们知道2002年9月1号为星期日,如果我们要想知道2002年9月10号为星期几,可以这样算:(0+(10-1))%7=(0+9)%7=2,即星期二。同样可算得2002年9月20号为:(0+(20-1))%7=(0+19)%7=5,即星期五。但是这样算需要把日期减1,不太方便,为了解决这个问题,我们可以假设每个月有一个0号,由于2002年9月1号为星期日,那么2002年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究竟是一个什么数了,下面我们就来解决这个问题。

我们已经知道2002年1月1号为星期二,它的前一天为星期一,那也就是说2002年的代码就是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

0

二月

A+3

3

三月

A+3

3

四月

A+6

6

五月

A+1

1

六月

A+4

4

七月

A+6

6

八月

A+2

2

九月

A+5

5

十月

A

0

十一月

A+3

3

十二月

A+5

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[] = {"Sunday",

"Monday",

"Tuesday",

"Wednesday",

"Thursday",

"Friday",

"Saturday"};

void main()

{

int Y;

int M;

int D;

int A;

printf("\nEnter year:");

scanf("%d",&Y);

printf("\nEnter month:");

scanf("%d",&M);

printf("\nEnter 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("\nI´s a %s.\n\n",week[A]);

}

(附:此文作于2002年9月,曾寄给《

论坛精华帖

万年历插件软件测试,一个计算万年历的简单程序相关推荐

  1. 如何用python写一个计算日期间隔的程序?

    如何用python写一个计算日期间隔的程序? 文章目录 如何用python写一个计算日期间隔的程序? 前言 问题梳理 问题解决 写在后面 前言 为什么想起来写一个这样的程序呢? 前几天聊天的时候,突然 ...

  2. 一个使用指针的简单程序

    一个使用指针的简单程序 /* 一个使用指针的简单程序 */ #include <stdio.h> void main() { int number = 0; //一个出初始化为0的整形变量 ...

  3. 一个计算数独的小程序

    一个计算数独的小程序 #include<iostream> #include <string> #include <fstream> #include <cs ...

  4. Pyqt5入门--用qtdesigner设计一个计算屏幕PPI小程序(qtdesigner/pyuic/pyinstaller/python)

    本文利用python中的pyqt5包,设计一个计算PPI小程序的界面,再利用pyuic将界面的ui文件转为py文件.再新建一个py文件继承界面py文件中类,并定义每一个按钮对应的函数,完成后利用pyi ...

  5. 万年历插件软件测试,万年历软件测试报告

    万年历软件测试报告Tag内容描述: 1.1 项目名称 中华万年历项目名称 中华万年历 软件测试方案软件测试方案 班级 班级 软件软件 1212 日期 日期 20142014 年年 1212 月月 1 ...

  6. python猜数游戏在程序中预设一个_一道Python简单程序结构练习题

    1.猜数游戏. 在程序中预设一个0~9之间的整数,让用户通过键盘输入所猜数字,如果大于预设的数, 显示"遗憾,太大了":如果小于预设的数,显示"遗憾,太小了": ...

  7. C语言--不使用库函数,利用指针编写一个计算字符串长度的程序

    题目:编写一个函数计算一个字符串的长度,输入输出在主函数中完成 以下两个例程仅供参考: #include <stdio.h> int Strlen(char *str)//不使用库函数,利 ...

  8. 用JAVA语言写一个计算员工月工资的程序

    一.任务需求 某公司分为多个部门,每个部门有一个经理和多个员工,每个员工根据职称发基本工资.员工的工资由基本工资,日加班工资,日缺勤工资等组成.具体需求如下所示: 员工的基本信息,包括部门,职务,职称 ...

  9. python计算一元二次_Python小程序-写一个计算一元二次方程的程序函数

    题目要求: 请定义一个函数quadratic(a, b, c),接收3个参数,返回一元二次方程:ax^2 + bx + c = 0的两个解. 程序代码: 这只是一个函数,如果你不调用它的话,是不会产生 ...

  10. 24点游戏java_使用java编写计算24点游戏程序

    初学java,编写了一个计算24点的程序,时间有限,有些粗糙,不过可以使用. //-------------Cal24.java--------------- //计算24点程序 //作者:徒步天下( ...

最新文章

  1. 深度卷积生成对抗网络
  2. ace+arm+linux,用NDK编译ACE在Android上运行
  3. android开发之Glide加载图片之url转bitmap的方法
  4. react方法返回html_React全家桶之React基础(推荐新手必看)
  5. Python3.x的print()输出问题
  6. No resource found that matches the given name 'android:Theme.Material.Light.DarkActionBar'
  7. Python使用requests发送post请求
  8. 织梦采集工具-织梦CMS采集教程
  9. Github实用浏览器插件推荐
  10. Thymeleaf中的ajax传参实例
  11. linux 上supervisor的进程管理工具的使用
  12. linux远程客户端软件,rdesktop(Linux下面的远程桌面客户端)
  13. 提供在Linux上运行最新版腾讯QQ与TIM的解决方案 Easiest Way to Run QQTIM on Linux
  14. 文化中国 系列一:明朝的那些人儿
  15. 快手2020校园招聘秋招笔试--工程C试卷 (编程题题解全)
  16. 从阅文合同风波,看IP源头与网文产业的下一站
  17. 你还在为不会FreeStyle而烦恼吗?抓取数据,自制歌词
  18. layui动态生成的手风琴实现默认第一个展开+鼠标悬浮展开
  19. Android 获取系统信息 手机号码 所在国家码
  20. Day43-Java面试系列(七)- Redis面试专题

热门文章

  1. javascript:js+css实现加载特效
  2. Spring Boot实现 文件上传与下载,包括前端界面实现
  3. gitignore文件的几种写法,Git忽略文件规则的配置方法
  4. 论文笔记_S2D.21_2014-CVPR_单张图像的离散-连续深度估计
  5. 视觉SLAM十四讲_3-李群和李代数
  6. ML/DL-复习笔记【一】- 数学基础(线性代数、概率论、数值分析)
  7. 如何使用文件的fseek函数对文件指针进行操作
  8. 解决Hbase的几个常见bug
  9. Hadoop2.2.0 + HBase0.96 伪分布式安装
  10. 关于u8, u16, u32, u64