中华农历论坛知识讨论区历法知识 → [原创]计算某日星期、干支的统一方法及公历转换成农历的公式


  共有23021人关注过本帖树形打印

主题:[原创]计算某日星期、干支的统一方法及公历转换成农历的公式

帅哥哟,离线,有人找我吗?
tgs28
  1楼 个性首页 | QQ | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:新手上路 帖子:5 积分:279 威望:0 精华:0 注册:2006/9/27 2:14:00
[原创]计算某日星期、干支的统一方法及公历转换成农历的公式  发帖心情 Post By:2006/10/2 9:14:00

计算某日星期、干支、农历日期的统一方法及公历转换成农历的公式

作者:谭笑风

为方便叙述,首先介绍两个函数
高斯函数:f(x)=[x],[x]表示不超过数x的最大整数,
那么对数x进行取整有三种方法:用高斯函数分别表示为
去尾法取整f(x)=[x];进一法取整f(x)=-[-x];四舍五入法取整f(x)=[x+0.5].
求余数函数:f(x)=xmodt,表示x除以t后所得的余数(即mod表示余数运算)
且被除数x=除数t*商+余数,所以有x=t*[x/t]+xmodt

如果以某年的1月1日为这一年第1天,那么这一年2月1日就是第32天……
如果设月份数为m,日期数为d,求m月d日是这一年的第几天(即这一天的序数),
这也容易算出,但能否给出个公式,把m,d代入公式直接求出序数g(m,d)呢?
下面来推导这个公式:
要求出序数g(m,d)只需把日期d加上这个月之前各月天数的总和g(m)即可,
比如说求1月份某日序数,把日期加0即可,
求2月份某日序数,把日期加31即可……
容易得出平年和闰年的1-12月份的月前天数总和g(m)分别是:
月份``m` ,1,`2, `3,`4, ``5, ``6, ``7, ``8, ``9, `10,`11, `12。
平年g(m),0,31,59,90,120,151,181,212,243,273,304,334。
闰年g(m),0,31,60,91,121,152,182,213,244,274,305,335。
下面来求这个月前天数总和g(m)的表达式,
假设(1)如果一年中的每个月都是30天,很容易得出月前天数总和g(m)为30m-30,
假设(2)如果一年中的单月都是31天,双月都是30天,
月前天数总和比假设(1)每个双月多一天,在假设(1)基础加[m/2],(即对m/2取整)
即可以得出这种情况下g(m)为30m+[m/2]-30,
假设(3)如果一年中8月以前的单月都是31天,双月都是30天,
并且8月及其以后的单月都是30天,双月都是31天,
月前天数总和比假设(2)中9月份及其以后每个月多一天,在假设(2)基础加[m/9],
即可以得出这种情况下g(m)为30m+[m/2]+[m/9]-30,
假设(3)跟实际情况已经很接近了,只差2月份的天数不同,
先考虑平年时的情况,2月份是28天,比假设(3)中少两天,
所以当m=1,2时g(m)为30m+[m/2]+[m/9]-30,
当m≥3时,g(m)为30m+[m/2]+[m/9]-30-2=30m+[m/2]+[m/9]-32,
可以用式子[2/m]和[1/m]把m=1,2时的情况化到上式当中,即得
平g(m)=30m+[m/2]+[m/9]-32+([2/m]-[1/m])*2,由此还可得闰年时
闰g(m)=30m+[m/2]+[m/9]-31+([2/m]-[1/m]),
设年份数为y,所以这个g(m)的统一式还和y有关。
前面已定义f(x)=xmodt表示x除以t后所得的余数,则闰年的条件可以这样来表述:
已知当ymod4=0且ymod100≠0或ymod400=0时,y年才为闰年,
由开篇介绍可知对(ymodt)/t用进一法取整表达式为-[-(ymodt)/t],
其含义为当ymodt=0时,-[-(ymodt)/t]=0;当ymodt≠0时,-[-(ymodt)/t]=1,
再由开篇x=t*[x/t]+xmodt可得-[-(ymodt)/t]=-[[y/t]-y/t],
令m(y)=-[[y/4]-y/4]+[[y/100]-y/100]-[[y/400]-y/400],
那么可以得出当y年是闰年时,m(y)=0,当y年不是闰年时,m(y)=1,
以上几式都可以用讨论的方法加以证明,证明从略。
将m(y)应用到上面的g(m)式中,可以得到g(m)的统一式:
g(m)=30m+[m/2]+[m/9]-31-m(y)+([2/m]-[1/m])*(1+m(y)),
所以g(m,d)=g(m)+d=30m+[m/2]+[m/9]-31-m(y)+([2/m]-[1/m])*(1+m(y))+d。

假设从公元前一年到现在的历法都是现行历法(格里高利历法),
即公历置闰方法未变,都是4年一闰且100年不闰400年又闰,
实际没有公元0年,现在假设有公元0年,并把公元0年1月1日设为第1天(序数为1),
那么公元1年1月1日就是第367天(序数为367)……
但能否给出个公式g(y,m,d),把y,m,d代入公式直接求y年m月d日这一天的序数呢?
下面来推导这个公式:
要求出序数g(y,m,d)只需把g(m,d)加上这一年之前的天数总和g(y),
假设(1)如果每年都是365天,很容易得出某一年之前的天数总和g(y)为365y,
假设(2)如果每4年一闰,即每4k+1的年份的序数都比假设(1)多一天,
由此可以得出g(y)为365y+[(y-1)/4]+1=365y+[y/4]-[[y/4]-y/4]
[(y-1)/4]+1=[y/4]-[[y/4]-y/4]可以用讨论的方法加以证明
由此可以得到g(y)的表达式为
g(y)=365y+[y/4]-[[y/4]-y/4]-[y/100]+[[y/100]-y/100]+[y/400]-[[y/400]-y/400],
上面有m(y)=-[[y/4]-y/4]+[[y/100]-y/100]-[[y/400]-y/400],
所以g(y)=365y+[y/4]-[y/100]+[y/400]+m(y),
g(y,m,d)=365y+[y/4]-[y/100]+[y/400]+m(y)+g(m)+d,
g(y,m,d)=365y+[y/4]-[y/100]+[y/400]+30m+[m/2]+[m/9]-31+([2/m]-[1/m])*(1+m(y))+d。
根据这个式子很容易求出任意两天之间相差的天数是多少,
即分别求出两天的序数之后作差即可。

为方便计算,下面来化简这个式子
设公元y年m月d日(y≥1582且y+m/10≥1583且y+m+d/15≥1593,1≤m≤12)
设公元y年年份的末两位数为b(b=y-[y/100]),
年份去掉末两位数后剩下的数为a(a=[y/100]),即有y=100a+b。
设f(y)=365y+[y/4]-[y/100]+[y/400],将y=100a+b代入式中得
f(y)=36500a+365b+[25a+b/4]-[a+b/100]+[a/4+b/400]
b为年份的末两位数,所以0≤b<100,所以[b/100]=0,b/400<1/4,
用讨论的方法(设a=4k+0,1,2,3)可以证明[a/4+b/400]=[a/4],所以
f(y)=36500a+365b+25a+[b/4]-a+[a/4],
f(y)=36524a+[a/4]+365b+[b/4],所以
g(y,m,d)=36524a+[a/4]+365b+[b/4]+30m+[m/2]+[m/9]-31+([2/m]-[1/m])*(1+m(y))+d。

设f(m)=30m+[m/2]+[m/9]+([2/m]-[1/m])*(1+m(y))+ε,(ε为一待定常数项)
设f(y,m,d)=f(y)+f(m)+d,则
f(y,m,d)=36524a+[a/4]+365b+[b/4]+30m+[m/2]+[m/9]+([2/m]-[1/m])*(1+m(y))+ε+d,
则f(y,m,d)就是公元y年m月d日一个相对的序数,
如果以某个历法周期p为模(除数),对进行求余数运算就可以求出某一天的是这个周期的哪一天了,
(1)如果以7为模,就可以求某一天星期几,
f(y,m,d)≡36524a+[a/4]+365b+[b/4]+f(m)+d (mod7),
≡5a+[a/4]+b+[b/4]+2m+[m/2]+[m/9]+([2/m]-[1/m])*(1+m(y))+ε+d (mod7),
然后对照历书就可以得出ε的值,
在这里f(m)是以公式的形式给出的,如果能直接记住每个月f(m)(mod7)的值,
会使计算更加快捷的,总之记的数据越多,算起来越快。
(2)如果以60为模,就可以求公历某年某月某日的干支序数,
f(y,m,d)≡36524a+[a/4]+365b+[b/4]+f(m)+d (mod60),
f(y,m,d)≡44a+[a/4]+5b+[b/4]+f(m)+d (mod60),
f(y,m,d)≡4*((11*(amod15))mod15)+[a/4]+5*bmod12+[b/4]+f(m)+d (mod60),

1-12月对应的f(m)的余数分别对应10,41,9,40,10,41,11,42,13,43,14,44;
闰年的1,2月份要减去1,最后求出的结果1-59分别对应干支甲子-壬戌,0对应癸亥,
即求出的结果用10除求余数,余数为0-9时分别对应天干:癸甲乙丙丁戊己庚辛壬,
求出的结果用12除求余数,余数为0-11时分别对应地支:亥子丑寅卯辰巳午未申酉戌亥,
当a=19时,44a+[a/4]≡0(mod60);当a=20时,44a+[a/4]≡45(mod60);
记住世纪的余数0和45就能很快算出上下100年某天的干支了,
如1949年10月1日干支序数为0+5*49mod12+[49/4]+43+1≡5+12+43+1≡61≡1(mod60),
所以新中国成立的这一天是甲子日!
再如2006年10月1日干支序数为45+5*6+[6/4]+43+1≡15+1+43+1≡0(mod60),
所以这一天是癸亥日,
也可以不用60作模,而分别用10和12作模对f(y,m,d)求余数,需要计算两次才能求出干支,
不知道这两种算法哪一种快,我还没有比较过。
(3)如果以28为模,就可以求某日对应的廿八宿,
当然廿八宿也可以根据星期和干支用中国剩余定理算出来。
(4)如果以29.5306为模,则可以比较精确的估计出公历某年某月某日的农历日期,
f(y,m,d)≡36524a+[a/4]+365b+[b/4]+f(m)+d (mod29.5306),
≡[a/4]-5.3522a+10.6328b+[b/4]+0.4694m+[m/2]+[m/9]+([2/m]-[1/m])*(1+m(y))+ε+d(mod29.5306)

据说目前还没有把公历转换成农历的公式,我想上面这个公式应该算是把公历转换成农历的公式了,
如果把ε取一恰当的值,再把所得的结果四舍五入,也许会得到农历日期的精确值,
这需要计算来验证,粗略算了一下,2000年的ε值在6.0134和6.0746之间,
如果得不到农历日期的精确值,我猜想ε对于每年都是不同的值,并且ε是年份y的函数,
如果也不成立的话,就需要换成更精确的周期29.53058867+0.0000000019(y-1900)来支持了,
计算起来更为麻烦,不过用计算机算起来也许很快,只是我不会编程,暂时没法验证。

另外,对于儒略历y年m月d日,有8≤y≤1582且y+m/10≤1583且y+m+d/4≤1593,
此时f(m)=30m+[m/2]+[m/9]+ε+([2/m]-[1/m])*(1-[[y/4]-y/4]),(ε为一待定常数项)
f(y)=36525a+365b+[b/4],设f(y,m,d)=f(y)+f(m)+d,则
f(y,m,d)=36525a+365b+[b/4]+30m+[m/2]+[m/9]+([2/m]-[1/m])*(1-[[y/4]-y/4])+ε+d,
则f(y,m,d)就是公元y年m月d日一个相对的序数,
应用这个式子可以计算儒略历时的星期和干支等数据,不再赘述。


支持(0中立(0反对(0单帖管理 | 引用 | 回复 回到顶部
帅哥哟,离线,有人找我吗?
geoh
  2楼 个性首页 | 信息 | 搜索 | 邮箱 | 主页 | UC


加好友 发短信
等级:新手上路 帖子:24 积分:425 威望:0 精华:0 注册:2006/8/24 19:38:00
  发帖心情 Post By:2006/10/5 22:36:00

误差比较大,正确的算法是:

例如2006年 先计算出2006年大寒的时间(具体太阳黄经求时间,) 然后计算大寒后的第一个朔日(VSPOS87算法),就是2006春节,嘿嘿,天文算法就是这样的!这样,所有问题都解决了,只是没计算机,人工算不出来!嘿嘿!


支持(0中立(0反对(0单帖管理 | 引用 | 回复 回到顶部

返回版面帖子列表

[原创]计算某日星期、干支的统一方法及公历转换成农历的公式








签名