第三章 回历计算

概述:

·开始日始为:1年1月1日,对应公历622年7月16日。
·在回历中1个闰周为30年,其中平年354天每年,闰年355天,1闰周之中有11个闰年,置闰周期为30年。
·闰年的分布:1闰周中的第2、5、7、10、13、16、18、21、24、26、29年。
·每年12个月,单数月30天,双数月29天,如果是闰年第12月也是30天。
·可见:1闰周有12*29.5*30+11=10631天

为了表述方便,我们临时定义了几个概念:

·INT(a)函数反回小于等于a的最小整数。
·总积日 n:从公元622年7月16日起连续按日计数。积日从0开始,622年7年26的积日为10。
若d0是J2000.0起算的儒略日数,那么 n = d0 + 503105
·周内积日A:某日相对于周首的偏移日数。
·年内积日B:某日相对于年首的偏移日数。
·月内积日d:某日相对于月首的偏移日数。

·周序数k,某一周的周首相对于回历开始日偏移的周数
·年序数y,某一年的年首相对于该年所在周的周首编移的年数
·月序数m,某一月的月首相对于该月所在年的年首编移的月数
·日序数d,某一日相对于该日所在月的月首编移的日数,它相当于月内积日。

由J2000.0起算的儒略日d0求,求回历

n = d0+503105

k = INT( n/10631 )

A = n -k*10631

y = INT( (A+0.5)/354.366 )

B = A - INT( y*354.366+0.5 )

m = INT( (B+0.11)/29.51 )

d = B - INT(29.5*m+0.5)

最后,年记做 y+1+k*30,月记做 m+1,日记做 d+1

已知周序数n、年序数y、月序数m、日序数d,求总积日k

k = 10631*n + INT(y*354.366+0.5) + INT(29.5*m+0.5) + d


已上算法的推导

一、已知总积日n,求周序数k及周内积日A

周序数:k = INT( (n+0.01)/10631 ) ……(式1)

周内积日:A = n -k*10631 ……(式2)

上式中多了个0.01是为了防止整数运算时出错,这里称之为截断补偿。因为计算机做除法时,即使用够整除,它也未必得到整数结果,如0.22/0.22的结果可能是0.99999999999999994,取整计算后得0,而正确值应是1。一些特殊小数,如0.5、0.25、0.125等2的整数次方组合的数可以被计算机精确表示,不会发生截断,所以这里可以不加0.01,即k = INT( n/10631 )。

二、已知周内积日A,求年序数y及年内积日B

(1)先求年序数

  平均每年354.366日,所以 c = D/354.366,考虑到序数为整数,则 y = INT(c),然而这种算法在年末或年首可能置闰问题造成y误差1,我们列表如下:

年序y	积日A	c
0年首	0	0
1年首	354	0.99896717
2年首	709	2.00075628
3年首	1063	2.99972345
4年首	1417	3.998690619
5年首	1772	5.00047973
6年首	2126	5.9994469
7年首	2481	7.00123601
8年首	2835	8.00020318
9年首	3189	8.999170349
10年首	3544	10.00095946
11年首	3898	10.99992663
12年首	4252	11.9988938
13年首	4607	13.00068291
14年首	4961	13.99965008
15年首	5315	14.99861725
16年首	5670	16.00040636
17年首	6024	16.99937353
18年首	6379	18.00116264
19年首	6733	19.00012981
20年首	7087	19.99909698
21年首	7442	21.00088609
22年首	7796	21.99985326
23年首	8150	22.99882043
24年首	8505	24.00060954
25年首	8859	24.99957671
26年首	9214	26.00136582
27年首	9568	27.00033299
28年首	9922	27.99930016
29年首	10277	29.00108927

从列表中发现,正常情况下,c的整数部分应从0开始顺序增加到29。而计算的结果却不是。从表中看出,只要将n的值加一点点,就可以使c的值正常。算式可改写为:

c = (A+0.5)/354.366,即:

y = INT(c) = INT((A+0.5)/354.366) ……(式3)

上式比原来的值多了一个0.5,我们不能增加太多,否则年首正常了,年末却发生错误。把上表中的积日全部减1后重新计算可得年末的年序数,并检查是否正确(正确值应为-1到28)。笔者用Excel软件调试,确定取值0.5是可靠的。

(2)接下来求年内积日B

每年至少有354天,所以年内积日大约为 B = A - y*354,然而这种算法没有考虑因闰年对积日的影响。在回历中,30年置11闰,平均每年354.366日。小数0.366正是"闰的速度",即每年闰了0.366日。这样,y年后闰了c = 0.366*y日,我们对f取整得到置闰日数。不过,如此计算的结果与历法中规定的闰年不会发生在相同的年份。可以使用Excel计算并比对,不难发现,只要加上0.5日就可解决问题。下表中e是按照历法规定的的闰年进行积累的置闰日数,置闰积数的拟合算式改写为 c = 0.366*y + 0.5,从下表中看出这样c的整数部分与就是e

y年序	e积数	c(拟合)
0	0	0.5
1(闰)	0	0.866
2	1	1.232
3	1	1.598
4(闰)	1	1.964
5	2	2.33
6(闰)	2	2.696
7	3	3.062
8	3	3.428
9(闰)	3	3.794
10	4	4.16
11	4	4.526
12(闰)	4	4.892
13	5	5.258
14	5	5.624
15(闰)	5	5.99
16	6	6.356
17(闰)	6	6.722
18	7	7.088
19	7	7.454
20(闰)	7	7.82
21	8	8.186
22	8	8.552
23(闰)	8	8.918
24	9	9.284
25(闰)	9	9.65
26	10	10.016
27	10	10.382
28(闰)	10	10.748
29	11	11.114
30	11	11.48

所以有 e = INT(c) = INT(0.366*y+0.5),式中y指偏移周首的年数(相当于年序数)

因此:B = A - y*354 - e = A - INT(y*354.366+0.5) ……(式4)

(3)判断y年是否为闰年

如果该年的置闰积累数的拟合值满足 d-INT(d) > 0.634 则是闰年(从上表中d的变化规律得到)。

三、已知年内的积日B,求月序数m及月内积日d

(1)求月序数m

如果一年只有354天,算法很简单: c = B/29.5,然后计算 m = INT(c),而事实上,一年可能是354天也可能是355天。当为355天时,使用上式最后一天将会计算为第13个月(月序数为12),如下表所示(闰年):

月序m	积日B	c=B/29.5
0月首	0	0
1月首	30	1.016949153
2月首	59	2
3月首	89	3.016949153
4月首	118	4
5月首	148	5.016949153
6月首	177	6
7月首	207	7.016949153
8月首	236	8
9月首	266	9.016949153
10月首	295	10
11月首	325	11.01694915
11月末	354	12(此处出错)

解决方法:

对B做一个线性补偿,补偿值为小量e。当B<325(m<11)时,e>0,当B>325时e<0。通过这种补偿,当m<11时c时增加了一点,反之c减小了一点,这样,表中最后一行c的整数部分减小1,其它各行c的整数部分保持不变,c的值全部正确了。我们还应注意,不管m取0到12的任何值时,e的值不能超0.5。比如首月的月末,c=B/29.5=29/29.5=0.983,这是正确的,如果B补偿了0.5,那么 c=29.5/29.5=1(变成第2月,显然确误)。我们设e=a*(325-B),a是我们选取的一个正常数,同时因e<0.5,所以a*(325-0)<0.5,得325*a<0.5

c = (B+e)/29.5
= (B(1-a) + a*325)/29.5
≈(B+a*325) / (29.5+29.5*a)
  如果用a代a*29.5,那么
c ≈(B+11*a) / (29.5+a),式中0<11*a<0.5

  当取a=0.01时,11*a=0.11<0.5
m = INT(c) = INT((B+0.11)/29.51) ……(式5)

(2)求月内积日d

因为m月占用了 INT(29.5*m+0.5),所以

d = B - INT(29.5*m+0.5) ……(式6)

四、综合,已知总积日n,求周序数k、年序数y、月序数m、日序数d(即:月内积日)

按 (式1)到(式6)连续读算

k = INT( n/10631 )

A = n -k*10631

y = INT( (A+0.5)/354.366 )

B = A - INT( y*354.366+0.5 )

m = INT( (B+0.11)/29.51 )

d = B - INT(29.5*m+0.5)

最后:

年记做 y+1+k*30

月记做 m+1

日记做 d+1

五、综合,已知周序数n、年序数y、月序数m、日序数d,求总积日k

k = 10631*n + INT(y*354.366+0.5) + INT(29.5*m+0.5) + d

黄历查询
1
2345678
9101112131415
16171819202122
23242526272829
3031