正确的坂本algorithmfind星期几
我使用Sakamoto的algorithm来查找给定date的星期几。 有人可以告诉我这个algorithm的正确性吗? 我只是想从2000年到2099年。
给出了维基百科的algorithm供参考。
int dow(int y, int m, int d) { static int t[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4}; y -= m < 3; return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7; }
那么,你可以通过查看它是正确的…假设t[]
数组是正确的,你可以用12次抽查(使用任何一天/一年的每月一次)来validation。
y -= m < 3
是一个很好的把戏。 它创build了一个“虚拟年”,从3月1日开始,到2月28日(或29日)结束,将额外的一天(如果有的话)放在年底 。 或者说,在去年年底。 例如,2011年3月1日开始虚拟年,2月29日结束,2012年虚拟年将从3月1日开始,到2月28日结束。
通过在虚拟年份的末尾添加闰年的附加date,其余的expression式被大量简化。
我们来看一下总和:
(y + y/4 - y/100 + y/400 + t[m-1] + d) % 7
正常的一年有365天。 这是52周加1天。 所以一般来说,一周的每一天都是每天转一天。 这就是y
这个词的贡献。 它每年增加一个。
但是每四年都是一个闰年。 那些每四年贡献一天。 由于使用了虚拟年份,我们可以只添加y/4
来计算y
年内发生了多less次闰日。 (请注意,这个公式假设整数除法。)
但这不太对,因为每一百年都不是闰年。 所以我们必须减去y/100
。
除了每四百年又是一个闰年。 所以我们必须添加y/400
。
最后,我们只是添加月份d
和取决于月份的表格的偏移量(因为年份内的月份边界是相当随意的)。
然后把整个事情模7,因为这是一个星期是多久。
(例如,如果星期是八天,那么这个公式中会有什么变化?显然,这将是mod 8,同样y
也需要是5*y
,因为365%8 == 5。 t[]
需要调整,就是这样)。
顺便说一下,维基百科的日历“9999之前的好”是完全随意的。 无论是十年,一百年,一千年还是一百万年,这个公式对我们来说都是有好处的。
[编辑]
上述论点本质上是归纳certificate。 也就是说, 假设公式适用于特定的(y,m,d),则certificate它适用于(y + 1,m,d)和(y,m,d + 1)。 (其中y是3月1日开始的“虚拟年份”)。所以关键问题是,从一年到下一年,这个总和是否会变化正确? 在了解闰年规则的情况下,以及在年末有额外一天的“虚拟年份”,它是微不足道的。
最近我在这里写了关于这个algorithm的博客文章。
algorithm背后的基本思想是在2月份和1月份从上一年的 12月31日算起。 其他所有月份我们将从当前年度12月31日的星期几开始计算。我们先用两个步骤先计算本月前一个月的最后一天的星期几,然后再加上d
模七。
31 Dec 1 BC是星期天,编码为0,星期一是1等,所以我们有: 0 + y + y/4 - y/100 + y/400
这个用y -= m < 3
计算星期几31当年或去年的12月(取决于月份)。 注意: 365 % 7 == 1
这解释了为什么我们写的是y
而不是365*y
。 最后一个组件d
是明显的,因为我们从上个月的上一个星期的星期几开始计数。
最后一部分需要解释的是数值,前两个值是从去年12月31日到本月开始的天数% 7
。 在剩下的几个月中,他们将从前一个月的月末到今年的十二月31日以七天为单位进行否定 。 换句话说,我们通过加模7来减去天数,例如(ab)%7 = (a+(7-b%7))%7
。
你可能会在我的博客文章中find更多的解释。