算法体系之二十天文台

By admin in 天文台 on 2019年2月15日

(接上篇)

       
所谓的“天文算法”,就是使用经典力学定律推导行星运转轨道,对轻易时刻的行星地方举行规范计算,从而拿到某种天文景色暴发时的时光,比如日月合朔这一天文现象就是太阳和月球的地心黄经(视黄经)差为0的那须臾间。可以统计任意时刻行星地点的一套理论就被号称星历表,相比较盛名的星历表有米利坚国家航空航天局下属的喷气推进实验室公布的DE体系星历表,还有瑞士联邦天文台在DE406基础上拓展的瑞士星历表等等。依照行星运维轨道直接总计行星地方一般不是很有利,更何况一大半私有天文总括用不上那么多精确的准则参数,于是天国学家在那一个星历表的基本功上演绎出了众多足以做简便计算,但是又能保证一定精度的行星运转理论,相比知名的有VSOP82/87阳光系行星运转理论和ELP-2000/8五月球运维理论,那两套理论在精度上业已很相近DE连串星历表了。关于什么行使那两套伦理举办天文历法计算,请参见“日历生成算法”连串文章的第3篇《用天文方法统计二十四节气》和第伍篇《用天文方法总结日月合朔》,本文介绍的公历年历推算是在早就由此天文算法拿到了标准的节气时间和日月合朔时间的根底上拓展的。

       
中国的官方纪时接纳的是华夏阴历(格里历),因而农历年历的演绎应以公历年的周期为着力,附上阴历年的消息,也等于说,年历以阴历的十一月十二日为初叶,至3月十二十2十一日得了,依照公历历法推导出的夏历日期新闻,附加在农历日期新闻上形成双历。日常情状下,多个公历年周期都无法完整地附和到2个农历年周期上,二者的谬误也不定点,由此不存在稳定的照应关系,也等于说,不设有从农历的日子到阴历日期的更换公式,只好依照公历的历法规则推导出农历日期与阴历日期的呼应关系。由阴历历法规则可以,上三个阴历年的寒露()所在的朔望月是上三个公历年的十10月(冬月),所以在进展节气计算时,需求总计包含上一年上巳节气在内的22个节气,才能对应上上三个公历年的十十一月和当下阴历年的十七月。在测算与之相应的初一时,考虑到有闰月的意况,要求从上一年上巳节气前的率先个朔日,延续总括1五个朔日才能担保覆盖八个夏至中间的一整年光阴,图(1)彰显了二〇一二年并未闰月的状态下朔日和春分的涉及:

天文台 1

图(1)没有闰月意况下朔日与中秋气关系图

图中上排数字是公历月的编号,赫色圆点代表朔日,银色三角形代表春龙节气。图(2)显示了二〇一一年有闰月的意况下朔日和春分的关系:

天文台 2

图(2)有闰月意况下朔日与上巳节气关系图

 

透过计算得到可以覆盖多个中秋气的具有初权且间后,就可以出手建立阴历日期与农历日期的附和关系。以图(1)所示的二零一三年为例,首先根据总结得到的1几个朔日(贰零壹壹年只会用到中间的前1肆个时间)时间,建立与二零一二年(阴历年)有关的朔望月关系表:

朔日编号

合朔时间

对应公历日期

月长

月名

1

01:35:39.90

2010-12-06

29

冬月

2

17:02:34.26

2011-01-04

30

腊月

3

10:30:42.67

2011-02-03

30

正月

4

04:45:59.44

2011-03-05

29

二月

5

22:32:15.13

2011-04-03

30

三月

6

14:50:31.79

2011-05-03

30

四月

7

05:02:32.51

2011-06-02

29

五月

8

16:53:54.10

2011-07-01

30

六月

9

02:39:45.06

2011-07-31

29

七月

10

11:04:06.43

2011-08-29

29

八月

11

19:08:50.09

2011-09-27

30

九月

12

03:55:54.64

2011-10-27

29

十月

13

14:09:40.97

2011-11-25

30

冬月

14

02:06:27.05

2011-12-25

29

腊月

15

15:39:23.99

2012-01-23

30

正月

表(2)二〇一一年朔望月与公历日期关系表

 

数码为1和2的多少个朔日之间的朔望月是十四月,因为春龙节气落在这几个朔望月,其他月的月名依次类推,5月的初一就是新年。输出公历和公历双历时,以月(公历)为单位,从每月第二,天初始,依次判断天天属于哪个朔望月,鲜明这一天的夏历月名,然后相比较这一天和这些朔望月的初一之间离开几天,记为公历日期。以2013年12月114日为例,这一天在二〇〇八年10月4日(2008年公历十十1月的初一)和二〇一二年三月25日之间(二零零六年农历五月的初一),查表(1)可见对应的夏历月是十一月,这一天和2008年3月六日偏离26天,因而这一天的阴历日期就是“廿七”。再以贰零壹叁年1月21九日(中秋节)这一天为例,查朔望月表得知10月1十九日属于从十二月1二二日始于的朔望月,那一个朔望月的月名是一月,而7月十四日就是月底,公历日期是初壹,4月底一就是元宵。

先来介绍多个函数,这八个函数分别用于总括节气和日月合朔发生的日子,函数算法的有血有肉讲述将在“日历生成算法”连串小说的第壹篇《用天文方法统计二十四节气》和第陆篇《用天文方法总结日月合朔》中牵线,此处只是不难介绍一下用法。首先是一个钱打二十四个结节气时间的函数:

    5 double CalculateSolarTerms(int year, int angle);

 

以此函数用于总括指定的年度(year参数)中,太阳在黄道上运转(视运动)到指定角度时的大运,angle可以设定节气发生时的角度,比如CalculateSolarTerms(二零一二,
270)就是计算2012年大暑的小时。那个函数再次回到的时间档次是儒略日,关于儒略日的验证请参见“日历生成算法”体系小说的第三篇《中国阴历(格里历)》。

       
接下去介绍统计日月合朔时间的函数:

    8 double CalculateMoonShuoJD(double tdJD);

 

本条函数再次来到指定时间附近的初一时半刻间,搜索的界定是tdJD参数指定时间的前一天到后29.5305天,tdJD参数和再次回到值的时日项目都是儒略日。

       
生成指定公历年份的公历和阴历的双历年历的流程如下:

 

天文台 3

图(3)计算公公历双历年历的流程

 

GetAllSolarTermsJD()函数从指定年份的指定节气开首,一而再计算三十几个节气时间,时间可以跨年份,内部判断过春龙节气后活动转到下一年的节气继续计算:

  139 void CChineseCalendar::GetAllSolarTermsJD(int year, int start, double *SolarTerms)

  140 {

  141     int i = 0;

  142     int st = start;

  143     while(i < 25)

  144     {

  145         double jd = CalculateSolarTerms(year, st * 15);

  147         if(st == WINTER_SOLSTICE)

  148         {

  149             year++;

  150         }

  151         st = (st + 1) % SOLAR_TERMS_COUNT;

  152     }

  153 }

start参数是节气的目录,定义二十四节气的目录如下:

   38 const int VERNAL_EQUINOX      = 0;    // 春分

   39 const int CLEAR_AND_BRIGHT    = 1;    // 清明

   40 const int GRAIN_RAIN          = 2;    // 谷雨

   41 const int SUMMER_BEGINS       = 3;    // 立夏

   42 const int GRAIN_BUDS          = 4;    // 小满

   43 const int GRAIN_IN_EAR        = 5;    // 芒种

   44 const int SUMMER_SOLSTICE     = 6;    // 夏至

   45 const int SLIGHT_HEAT         = 7;    // 小暑

   46 const int GREAT_HEAT          = 8;    // 大暑

   47 const int AUTUMN_BEGINS       = 9;    // 立秋

   48 const int STOPPING_THE_HEAT   = 10;   // 处暑

   49 const int WHITE_DEWS          = 11;   // 白露

   50 const int AUTUMN_EQUINOX      = 12;   // 秋分

   51 const int COLD_DEWS           = 13;   // 寒露

   52 const int HOAR_FROST_FALLS    = 14;   // 霜降

   53 const int WINTER_BEGINS       = 15;   // 立冬

   54 const int LIGHT_SNOW          = 16;   // 小雪

   55 const int HEAVY_SNOW          = 17;   // 大雪

   56 const int WINTER_SOLSTICE     = 18;   // 冬至

   57 const int SLIGHT_COLD         = 19;   // 小寒

   58 const int GREAT_COLD          = 20;   // 大寒

   59 const int SPRING_BEGINS       = 21;   // 立春

   60 const int THE_RAINS           = 22;   // 雨水

   61 const int INSECTS_AWAKEN      = 23;   // 惊蛰

 

节气索引乘以15就是节气在黄道上相应的度数。GetNewMoonJDs()函数从指定时间最先接连总计1多少个朔日时间,从第1个七夕气前的第3个朔日先河。十四个朔日能够形成1五个一体化的朔望月,保险在有闰月的景观下也能包括几个端午气:

  137 void CChineseCalendar::GetNewMoonJDs(double jd, double *NewMoon)

  138 {

  139     for(int i = 0; i < NEW_MOON_CALC_COUNT; i++)

  140     {

  141         double shuoJD = CalculateMoonShuoJD(jd);

  142         NewMoon[i] = shuoJD;

  143 

  144         jd += 29.5; /*转到下一个最接近朔日的时间*/

  145     }

  146 }

BuildAllChnMonthInfo()函数依照拾八个朔日时间组成拾伍个朔望月,依照附近朔日的区间统计出公历月天数用来判断大小月,并且从“十7月”初始相继为每一种朔望月命名(月建名称):

  170 bool CChineseCalendar::BuildAllChnMonthInfo()

  171 {

  172     CHN_MONTH_INFO info; //一年最多可13个农历月

  173     int i;

  174     int yuejian = 11;   //采用夏历建寅,冬至所在月份为农历11月

  175     for(i = 0; i < (NEW_MOON_CALC_COUNT – 1); i++)

  176     {

  177         info.mmonth = i;

  178         info.mname = (yuejian <= 12) ? yuejian : yuejian – 12;

  179         info.shuoJD = m_NewMoonJD[i];

  180         info.nextJD = m_NewMoonJD[i + 1];

  181         info.mdays = int(info.nextJD + 0.5) – int(info.shuoJD + 0.5);

  182         info.leap = 0;

  183 

  184         CChnMonthInfo cm(&info);

  185         m_ChnMonthInfo.push_back(cm);

  186 

  187         yuejian++;

  188     }

  189 

  190     return (m_ChnMonthInfo.size() == (NEW_MOON_CALC_COUNT – 1));

  191 }

 

CalcLeapChnMonth()函数根据节气和初一时间判定在八个元宵节气之间的阴历年是或不是有闰月,判断的按照就是看第3十个朔日是还是不是在第壹个七夕节气从前,即使第柒八个朔日发生在其次个清明节气以前,就证实在三个下元节气之间爆发了十四次朔日,需要置闰月。因为农历中十二个中气属于哪个阴历月是永恒的,因而置闰月的长河就是各种判断十一个中气是不是在相应的夏历月尾,假如本应有属于有些阴历月的中气却未曾落在那一个旧历月初,则这一个旧历月就是闰月,须要设置闰月标志,同时调整那一个月将来的月名。调整公历月名的法子就是月名减1、比如原先是十一月将要调整为十十月,那样就将十4个月对应上了十二个月名(其中多出去的贰个阴历月被命名为闰某月)。即便节气和初一发生在同一天,CalcLeapChnMonth()函数采取的是民间历法的条条框框,与当今历法一致:

  194 void CChineseCalendar::CalcLeapChnMonth()

  195 {

  196     assert(m_ChnMonthInfo.size() > 0); /*阴历月的初始化必须在这个之前*/

  197 

  198     int i;

  199

  200     if(int(m_NewMoonJD[13] + 0.5) <= int(m_SolarTermsJD[24] + 0.5)) //第13月的月末没有超过冬至,说明今年需要闰一个月

  201     {

  202         //找到第一个没有中气的月

  203         i = 1;

  204         while(i < (NEW_MOON_CALC_COUNT – 1))

  205         {

  206 

  207             /*m_NewMoonJD[i + 1]是第i农历月的下一个月的月首,本该属于第i月的中气如果比下一个月

  208               的月首还晚,或者与下个月的月首是同一天(民间历法),则说明第i月没有中气*/

  209             if(int(m_NewMoonJD[i + 1] + 0.5) <= int(m_SolarTermsJD[2 * i] + 0.5))

  210                 break;

  211             i++;

  212         }

  213         if(i < (NEW_MOON_CALC_COUNT – 1)) /*找到闰月,对后面的农历月调整月名*/

  214         {

  215             m_ChnMonthInfo[i].SetLeapMonth(true);

  216             while(i < (NEW_MOON_CALC_COUNT – 1))

  217             {

  218                 m_ChnMonthInfo[i++].ReIndexMonthName();

  219             }

  220         }

  221     }

  222 }

       
从理论上讲,本文介绍的算法在精度允许的限量内可以计算前后几千年的阴历年历,然则对北宋的夏历总结须要小心。首先是“平朔”和“定朔”的难题,西楚之前使用的是平朔方法定月尾,本文介绍的推断办法应用的是“定朔”方法,因而统计出的年历与北周在此从前的历史会不相同。此外,即是在西魏从此采纳“定朔”的历法,因为曹魏天文观测和测算受条件限制,或然不够标准,由此与今日用天文算法统计出的结果只怕并差距。所以对历史阴历的乘除应该以历史事实为主,天文计算为辅,当总计与历史差距时,要按照历史数据举办校勘。Calendar.exe是基于本文介绍的算法编写的日历小程序,没有太多的机能,紧借使为了验证算法,因为从没历史数据用于校对结果,由此不辅助1601年以前的阴历总计(约等于说依照天文算法总括出来的结果或然和实在历史上的历法不符)。

天文台 4

图(5)演示程序的界面

天文台, 

小知识1:民间历法和历理历法

   
新中国建立将来没有发布新的“官方阴历历法”,将历法和政治分离浮现了时代的进化,不过出于没有
“官方历法”,也引起了一部分标题。比如笔者国现行采纳的农历历法是《时宪历》,它来自梁国福临年间(公元1645)公布的《爱新觉罗·福临历》,它有四个不足之处:三个是日月合朔和节气的时刻以首都当地时间为准,相当于东经116度二十几分的地点时间,其节气和新月的洞察只适用于中原地区。其余经度的地点,因为日子的涉嫌,对导致日月合朔和节气时间的差距导致置闰和月顺序各差别。另壹个不足之处就是日月合朔时间和节气时间判定不准确,如若日月合朔时间和节气时间在当天,不管具体的时刻是还是不是有先后,一律将此节气算做新月尾的节气,这样一来,即使那么些节气是中气,就会潜移默化到闰月的安装。历理历法针对那两点进行了改正,对节气时间和日月合朔时间集合行使东经120度即东八区正规时,那样在其余时区的节气和置闰结果都是同样的,以东八区正式时为准。对于节气时间和日月合朔时间在当天的情事,精确统计到时、分、秒,唯有日月合朔时间在节气时间在此以前,这么些节气才含有在次月内。历理历法从理论上讲更合乎现代天农学的标准总结,不过急需专注的是,历理历法还是只是存在于理论上的历法,作者国现行的农历历法依旧是民间历法《时宪历》或《顺治帝历》。

 

 

小知识2:通式福星公式

“通式寿星公式”是前人整理出来的3个用于计算每年小暑天期的经验公式:

Date =
向下取整(Y * D + C) – L

个中,Y是年度,D的值是0.2422,C是涉世值,取决于节气和年度,对于21世纪,立春节气的C值是4.475,夏至节气的C值是20.646之类;

L是闰年数,其总计公式为:

L =
向下取整(Y/4) – 向下取整(Y/100) + 向下取整(Y/400)

 

用“通式福星公式”明确2013年小雪天期的历程如下:

L = int(2011/4) – int(2011/100) +
int(2011/400) = 502 – 20 + 5 = 487

 

Date = int(2011×0.2422+4.475)- 487 = 491 – 487 = 4

 

从而,2011年的小暑天期是七月三十日。

 

 

小知识3:总结节气和初一的经验公式

   
以一九零三年八月0日(礼拜天)为基准日,之后的天天与基准日的差值称为“积日”,
1901年二月七日的积日是1,以往的光阴各个类推,则计算第y年第x个节气的积日公式是:

 

F = 365.242 *
(y – 1900) + 6.2 + 15.22 *x – 1.9 * sin(0.262 * x)

 

中间x是节气的目录,0代表夏至,1表示小暑,别的节气如约顺序类推。

 

计量从1904年开端第m个朔日的公式是:

 

M = 1.6 +
29.5306 * m + 0.4 * sin(1 – 0.45058 * m)

 

 

小知识4:平朔和定朔

   
中国公历的朔望月长度是平均29.5305天,所以阴历月就有大月30天,小月29天之分,从先秦时代到西楚,公历历法均是使用大小月轮流交替的措施设置逐个阴历月的运气,唯有些情景下才面世两次三番四个大月的动静,采取那种艺术的历法就称为“平朔”。“平朔”历法不难,但是不可以确保日月合朔暴发在初一这一天,有或者是上月的月末一天,也有可能是本月尾二。南北朝时代,一种新的历法被提议来,那种历法严酷根据日月合朔为月尾制订阴历月,采取那种方法的历法就称为“定朔”。“定朔”历法严厉将日月合朔时间规定月中,因为月球公转是椭圆轨道,速度并不是均匀,所以会生出延续多少个大月或两次三番多少个小月的情形,导致“定朔”历法推广碰到很大的阻力,直到武周,中国历法才完美弃用“平朔”,改用“定朔”。

 

 

小知识5:二月首一和立上巳节气

   
立秋是二十四节气之首,所以大顺民间都以在“大暑”这一天过节,相当于现代的端午(中国太古即是节气也是节日的情状多多,比如立冬、夏至等等)。1912年,孙台州领导的新民主主义革命建立了中华民国,在从历法上正式把阴历四月中一定为“中秋”,把公历11月10日定为“岁朝”,相当于“新年”。农历年从初一发轫并未计较,但是阴历生肖年从哪一天开首却直接有顶牛,近年来多数人都以为“小寒”节气是旧历生肖年的开头。因为在中华太古历法中,十二生肖的乘除与奇门遁甲有很大关系,所以在“论奇门遁甲、计算廿四节气”的景观下,“立夏”节气应该是新生肖的早先。对于常见老百姓的话,习惯于认为九月中一是生肖年的初阶,因而,一月尾一和“大雪”节气之间出生的小孩子,在规定属相的时候就有点麻烦了。属牛还是属虎?那是个难题。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图
Copyright @ 2010-2019 亚洲必赢手机官网 版权所有