万书网 > 文学作品 > 程序员的数学思维修炼 > 5.2日历中的数学

5.2日历中的数学




日历就是利用余数来进行分组的一个例子。一周有7天,因此可将日期分为7组,每组对应一周中的一天。这样,按组竖向排列,就可得到一份月历。



5.2.1 n天后是星期几


如图5-2所示是2013年5月的月历,今天是5月3日,星期五,则7天之后(3+7)为5月10日也是星期五,而14天之后(3+7+7)为5月17日、21天之后(3+7+7+7)为5月24日、28天之后(3+7+7+7+7)为5月31日都是星期五。从图5-2中也可看到,这几天都位于月历星期五的同一列中。

图5-2

知道了这个规则,则可以很容易地推算出n天之后是星期几。

例如,若想推算出100天之后是星期几,则可考虑首先到了接近第100天时为星期五的那一天:在今天(5月3日)之后的第7、14、21、28、35、42、49、56、63、70、77、84、91、98天都为星期五。接着,可继续向下推算:

由此可知,今天之后的第100天为星期日。

其实,不用按上面的推算过程,通过计算余数可以更方便地计算出n天后为星期几,计算公式如下:

在以上算式中,我们不关注商q,只需要关注余数r即可。n除以7后的余数在0~6这7种情况,因此可分为7组,将这7个余数排列起来,再与当前的星期数对应,即可快速推出n天后为星期几。

例如,在上面计算100天后为星期几,可按以下公式进行计算:

接着按下面的形式列出余数0~6,将余数为0的下方填写与今日对应的星期数,然后向后循环,即可得到如图5-3所示余数与星期几的对应关系。

图5-3

当余数为2时,从上面的对应关系中得到100天后为星期日。

有了这种通过余数来推算星期几的方式,则可计算出任意天数后为星期几。例如,今天为星期五,1000天之后为星期几?

根据图5-3所示对应关系可知,1000天后为星期四。

需要注意的是,图5-3的对应关系是变化的,余数为0时对应的是当天的星期数。



5.2.2 下月的今天是星期几


如果要计算下月的今天是星期几,该怎么办?这时,由于没有距今天的天数,就不能直接使用前面介绍的方法进行求余数了。

其实,要计算星期几,最终还是必须转化到求7的余数上来。因此,要计算下月的“今天”是星期几,可以先计算下月的“今天”距离今天是多少天,然后就回到上面介绍的通过天数推算星期几的方法中了。

那么,下月的“今天”是怎么定义的呢?如果今天是2013年5月3日,下月的“今天”就是2013年6月3日,即只是增加月份,日期数值不变。不过,要考虑一个问题,就是如果今天是2012年12月3日,则下月的“今天”应该是2013年1月3日,年、月数值都要变化。

下月的“今天”距今天的天数是多少呢?

根据历法,每年的1、3、5、7、8、10、12月为大月,每月有31天,每年的4、6、9、11月为小月,每月30天,每年的2月的天数根据平年、闰年分别为28、29天。

根据以上历法知识,若今天是2013年5月3日,则下月的“今天”为6月3日。由于5月有31天,因此今天距离下月“今天”的天数也为31天,则可通过以下算式计算出余数:

余数为3,查询图5-3所示对照关系,可知道2013年6月3日为星期一。打开日历,可看到2013年6月的日历如图5-4所示,在这里可看到2013年6月3日为星期一。

图5-4



5.2.3 10年后的“今天”是星期几


增加点难度,10年后的“今天”是星期几,该怎么计算?

理论上,同样只需要计算出10年后的今天距离“今天”的天数,就可以很简单地推算出是星期几。可是,跨度为1月的天数比较好计算,也就可以很容易地推算出下月的今天是星期几。如果要横跨几年,该怎么计算呢?

可以从另一个角度考虑,我们只要寻找一个求公元n年m月k日是星期几的一个公式即可。这样,就不必再去关注两个日期之间相距的天数了。

前面我们已经介绍过,根据月大、月小、平年、闰年等关系,每月的天数是不一样的。月大、月小是有规律可循的,平年、闰年有规律吗?

我们知道,公历的年是以寒暑更替的周期(俗称回归年,即太阳相继两次过春分点所经历的时间)为基础的,但是,一回归年有365天5时48分46秒,其天数不是整数。如果一年的天数不是整数,对人们来说,使用起来很不方便。为了解决这个矛盾,公历制定了相应的设置闰年的法则,根据该法则就可判断是否为闰年。设年份为n,则判断n是否为闰年的法则如下:

如果n能被100整除,且能被400整除,则n是闰年;

如果n能被4整除,但不能被100整除,则n是闰年。

例如:

2000年是闰年(2000能被100和400整除);

1996年是闰年(1996能被4整除,不能被100整除);

1900年是平年(1900年能被100整除,但不能被400整除)。

根据历法知识我们知道,平年一年是365天,闰年一年是366天,则要求公元n年m月k日是星期几,只需要推算从公元1年至公元n年一共经历了多少个闰年。根据判断闰年的法则,可使用以下公式计算出n年共经历了多少年闰年:

在以上公式中,方括号表示计算的结果取整。以上算式中第一项表示能被4整除的年份数量,其中也包含了能被100整除的年份,但是能被4整除,且能被100整除的年份不是闰年,因此应减去能被100整除的年份(以上算式的第2项);但是这时减去能被100整除的年份时,将能被400整除的年份数量也减掉了,而这部分年份是闰年,因此还要加回去,第3项就是得到能被400整数的年份数量。

由于是计算到n年经历了多少年闰年,当然就不能将n年包含在内,所以使用(n-1),实际是判断从公元1年至公元n-1年(含)共有多少个闰年。

根据上面的公式可推出下面的公式,计算出距离公元1年1月1日的天数。


在上面公式中n为年份,c为公元n年m月k日在n年中的天数。

通过以上公式计算出S值,再用S值除以7,得到余数,余数为1则是星期一,余数为2则是星期二……,余数为0则为星期日,如图5-5所示(这是因为公元1年1月1日为星期一,所以推算得出图5-5所示的对应关系)。

图5-5

其实,上面的公式还可以简化为以下形式(即不乘365):

根据以上公式,计算2013年1月1日为星期几,首先计算S值:

接着将S的值除以7,得到余数:

所以,从图5-5中的对应关系可查得,2013年1月1日为星期二。

有了这个公式,计算10年后的“今天”是星期几就简单了。假设今天为2013年5月3日,则10年后的“今天”就是2023年5月3日。将数据代入上面的公可计算出S的值:

在上面公式中,后面那一串算式是计算2023年5月3日的天数,其中,有1、3月为大月,每月31天,2月为平月28天,4月为小月30天,5月还包含3天。

接着将S的值除以7,取余数:

从图5-5的对应关系可得出,10年后的“今天”(2023-5-3)为星期三。查询日历可看到,计算结果是正确的,如图5-6所示。

图5-6

可见,不管怎么变化,求星期几的操作都是以求余数为基础的。