APP下载

古代历法算法的计算机模拟

2018-06-11滕艳辉田卫军王鹏云

文化创新比较研究 2018年13期
关键词:枚举历法常数

滕艳辉,田卫军,王鹏云

(咸阳师范学院 数学与信息科学学院,陕西咸阳 71200)

历法是中国传统文化的重要组成部分。历法在历史学、地球物理学、天体物理学和考古天文学中发挥了很重要的作用。过去,大批天文史家和历史学家在古代历法解读与算法原理方面做了大量的工作。而要想更全面更直观的理解中国古代历法,对历法的推算过程进行模拟实验,对推算的结果进行复原是十分必要的。1980年代后,随着微型电子计算机的普及,历法研究者开始使用计算机对古代历法进行模拟和复原。[1-5]但截至目前,这方面的工作还仅是一个开端,较为深入的研究仍很少。本文试图讨论古代历法计算机模拟的可行性及实施思路和方案。

1 传统历法的算法特征

中国传统历法不仅仅是给出历日计算,颁行历书,它的更重要的作用是推算太阳运动、月亮运动、日月交食、五行运动以及各种天象的发生时间和在天空的位置。传统历法的是由天文常数和算法推步构成的,其本质是中国数理天文学。它的每一个推算过程都是是数值算法。每个具体算法都有确定的名称。每一个推算过程也有明确的目的,并且都能在有限步内完成,得到确定的结果。推算过程中所需要参与运算的各参数要么是历法给出的天文常数,要么是在前面算法中已经计算出来的结果。

古代历法中的算法以文字的形式一般描述成 “求……:置……,为……”,如历法记载“各以入气、入转朏朒定数朏减朒加经朔、弦、望小余,满若不足,进退大余,命甲子,算外,各得定日及余。”[6]这段术文是《崇天历》求“朔望定日”(即定朔定望时刻)的术文,所需要的参数是经朔、望小余和入气、入转朏朒定数,而这几个值在此算法之前已经求得,于是该算法就可转化为公式,并容易得到结果。因此,中国传统历法中的算法具有确定性,有穷性和可解性,与现代计算机科学中的算法性质相同。历法推算中同样使用的顺序、分支和循环的基本算法结构。因此,使用计算机来模拟古代历法中的算法是可行的。

中国传统历法使用的积年数都很大。特别是唐代以后,有的积年数甚至达到几千万。这使得历法推算的工作量非常大。在古代,使用传统历法具体推算的工具只有筹算和笔算,可想而知,这样的工作既耗时又耗力,而且还不能保证在推算中不出现错误。如果推算过程某个地方出现错误,错误出现的地方就非常不易查找,而且查找错误所耗的时间精力不亚于重新推算。而具有机械性、高效性和稳定性的电子计算机却很适合做这样的工作。

2 历法计算机模拟的思路

实现历法计算机模拟主的整体思路是:首先是全面整理古代历法,对其中的算术文进行校勘和梳理,并将其中文本形式的常数和表格进行数字化;然后是建立各算法之间的相互关系,确定输入输出参数,建立数据流图,在此基础上,将历法中的文字性描述的算法完全公式化,并完成程序流程图的设计;最后是选择程序开发工具,编写具体程序代码和软件交互的界面UI设计,并通过程序调试和软件测试,打包发布可用的古代历法计算机模拟的软件。

自汉代至明代,中国一共行用了100多部官方历法。我们需要根据历法的术文的完整性进行分类,指出哪些历法是可以进行模拟的,哪些是不可以的。有30多部传统历法的术文是完整的保存至今的。用计算机模拟这些历法也就相当于在复原古人的计算过程和计算结果。还有30部左右历法的术文大部分被保留下来,但缺少某些片段,通过对比其它完整历法,或是根据某些史料记载,如果能够修补,使之成为完整的历法,我们也可以模拟其算法和结果。例如,《大衍历》之后的《至德历》、《五纪历》和《正元历》的术文都没有被记载下来,但基本常数和表格都是完整,并且史书中记载,这些历法的算法与《大衍历》相同。对这些历法的模拟按照《大衍历》的算法就行了。其余几十部历法,有些仅是记载了少量的天文常数,有的甚至完全失传了。目前,我们还没有办法对这些历法进行模拟复原。

中国古代数理天文学的基本天文常数是回归年和朔望月,其它常数都是导出常数,可以使用基本常数进行推算。[7]为了方便具体算法中调用这些天文常数,我们事先将其整理好并进行存储。我们选择关系型数据库来存储这些数据,每一部历法单独建立一个数据库。每一个数据库里面建立一个名为“天文常数”的表。这个表将存储这部历法推算时用到的所有常数,并将历法的基本信息也作为记录存放其中。这个表的各列分别是“id、常数、常数值、备注……”等项目,表的每行就是一个常数的各项值等信息。

中国传统历法中还存在着为了计算方便而事先给出的表格。这些表格是为,在具体计算中需要那些数值,直接查表即可。表格主要有日躔表、月离表、七十二候表、赤道宿度表、24气圭表影长表、五星盈缩历表、五星段次表等。这些表格我们可以直接作为数据库的表格存储,表的名称、列名都按照历法给出的名字命名。

还有一些表格不存在于历法术文中,必须通过历法已经给出的构造方法建立好了才能进使用。每日日躔表、每日圭表影长表、每日日出分表、每日月亮迟疾表等就属于此类。这些表格我们也根据历法给出的表格布局建立相应名称和结构的表格,然后根据历法的推算,编写程序计算出数据,存于相应的表中,方便历法推步时随时调用。

此外,历法为了补充算法或表格而给出的一些独立数值,这些值虽然比较少,但很零散,如月亮在七日十四日二十一日的月离数据。这些数据我们也单独建立一个为“辅助表格”的表,根据各部历法的具体情况定义表格的结构。计算机模拟复原的结果也需要输出,我们在各历法的数据库里也建立了定朔表、太阳运行宿次表、月食表和日食表等表格。

3 古代历法计算模拟的实施方案

古代历法算法的计算机模拟是一个相对较小的软件,我们仅采用软件工程的思想进行总体设计和详细设计,没有必要完全按照工程化的步骤进行。

3.1 面向对象的总体设计

我们拟采用面向对象的程序设计,总体设计包括基本数据类,数据库操作,历法推步类和可视化图形界面设计等。在进行设计之前,我们需要给出算法模拟程序所涉及到的对象、变量以及类型名称的命名规则。对象的公共变量(属性)名称形式是“tc+变量名称”;对象及其子类名称形式是“to+对象或子类名称”;对象的公共函数(方法)名称形式是“tf_+方法名称”;枚举类名称“tm+枚举类名”,枚举值“etm+枚举文本”;所有名称的首字母都大写。

在“基本数据类”中,我们定义了基本运算类、枚举类和其它一些自定义数据类型。基本运算类定义了历法推算能用到的数值计算方法,如整数约分、实数取余、格式化数值结果(四舍五入等)和分数的比较等。计算机程序中不能直接将节气、时辰和干支这些历法特有的时间作为变量,我们将这些文字项作为枚举数值类型,使节气、时辰和干支对应于具体数字。例如干支枚举的定义如下。

Public Enum tmGanZhi

etmJIAZI=1‘甲子

etmYICHOU=2‘乙丑

……

etmGUIHAI=60‘癸亥

End Enum

时辰枚举类名是 “tmShiChen”,节气枚举类名是”tmJieQi”是定义。枚举类中,我们还定义了如何取得枚举记录的文字项。例如 “Public Function tf_RecGanZhi(ByVal ruqi As tmGanZhi)As String”就是将干支的枚举值转换成具体干支文字的方法。

历法推算的最终结果以及中间计算的有参考意义的结果都放在天文记录类里定义,其定义如下。

基本推步类是计算机模拟的核心部分。我们设计了气朔(toQishuo)、日躔(toRichan)、晷漏(toGuilou)、月离(toYueli)、交会(toJiaoshi)和火星(toHuoxing)等几个子类。传统历法有百部之多,行用长达2000年,不同时代和发展阶段的历法,其具体算法肯定会有所不停。在软件设计时,我们尽量为同一种推算设计通用的算法,能够使多部历法公用一个计算机算法。当然,如果不同历法间的同一推算方法完全不同,我们就为这部历法单独设计相应算法,与通用算法放在具体的推步类中。例如,交会类的定义如下。

Public Class toJiaoshi

Public tcJiaozhongf As Double'交终分

……

Public tcJiaoshu As Double‘交数

Public Function tf_GetShishenDy()As Double‘食甚时刻一般算法

Public Function tf_GetShishenDyctl()As Double‘《黄极历》食甚时刻算法

……

End Class

要说明的是,为了编制数据流图的方便,我们对每个类型的每个成员都给出一个编码,加以识别。因计算机模拟程序相对简单,我们这里同样不需要按照软件工程的方法建立数据字典。对对象的编码加以说明对程序的内容加以注释就可以了。

建立每一个推步类时,都要先解读每一个子算法,得到算法的输入和输出变量信息;建立整个历法推步的框架,找到各子算法在这个框架中的位置以及各子算法之间的相互联系;并明确各常数和算法的现代天文学意义。根据各算法的关系建立数据流图,完成整体设计。

3.2 详细设计与代码编写

要将总体设计的数据流图转化为可以编写代码的程序流程图,其前提是将历法中所有具体算法用现代数学公式表达出来。然而传统历法术文叙述极其简洁,历法制定时往往省略了或隐含了某些分支选择的条件、结果单位的换算和日常使用的简单算法等。历法的使用者是人,这些问题在用笔算或是筹算等人工操作时,是很容易被发现并处理的。但我们让机器代替人进行推算,如果直接根据术文去编写代码,不仅不能做到正确的模拟,甚至不能得到可执行的程序。我们必须根据上下文等技术手段补齐或明确这些条件,计算机才能识别。

例如,根据古人的时间概念,所有关于日期计算的结果整数部分大于60时,为了使结果能在一个干支序列内就要在已经算得的结果上减去60;在日食的计算中,如果计算日食初亏时间在日落以后或是复原时间在日出以前,即使有日食我们也不能看见的,这是前面所得的日食食甚和食分就都不能作为结果给出了,而是给出没有日食的结论。但关于上面的情况,大部分的历法术文都没有给出相应说明,因为这些对于历法使用者的人来说是非常直观的。

由于隋代以后的历法使用了更加庞大的上元积年数,在用计算机模拟的过程中,如果处理不当,就会产生很大的误差。例如,同一个算法,在不同历法中,其运算顺序可能不同,可能是先乘再除,也可能是先除再乘;还有些历法对计算结果小数部分取整,而有些则四舍五入。这些微小的不同处理方式,可能会被天文常数放大,造成模拟的误差增大。因此,代码编写中涉及到的各种运算和对计算结果的处理时,我们完全依照当时使用历法进行实际推算的习惯操作,使之与用筹算或笔算得到的结果相一致。我们拟采用Visual Basic 9.0作为古代历法算法计算机模拟的开发工具,编制出可视化的应用程序。

3.3 软件的生成与检测

虽然VB9编辑器和编译器的调试和编译功能可以提示我们某些程序编写上的错误,但运行中发生的错误是需要合理设计测试案例进行检测的。但问题是,古代历法家所提供的使用某部历法推算的全过程已经完全失传了,使用这些现成的结果作为程序检测时不现实的。那么我们将视线转向现存历史的有关使用历法进行推算的结果记录上面。

古代文献中有利用某些天象测验历法优劣的记载。这些记录就是当时人们使用某种历法进行实际推算的结果,我们正确复原的历法也一定能得到这样的结果。我们找到这些记录,并进行整理,确定这些记录是在什么时间使用什么历法推算什么天象,然后使用已经编好的某部历法的程序计算特定时刻的相应天象。当程序计算的结果与史载记录的结果相同时,就能说明我们对历法的解释和所编写的程序是正确的。当程序计算值与史载记录不相符时,我们要检查前面的工作是哪一个环节出了问题。如果仅是程序错误,我们要修改程序代码,重新调试和编译;如果是术文或常数解读错误,则要重复整个第整体设计和详细设计的过程,直到准确无误。

4 结语

过去,中国古代历法的主要研究方法是文献考证、算法解读以及对比评价。而随着原始资料使用上的限制,更需要研究方法上的突破。我们试图使用计算机为工具对古代历法进行研究,使对古代算法的研究方式从文献到文献的研究拓展到多学科多工具综合研究。我们根据古代历法的特点,阐明传统历法计算机模拟的必要性和可行性,给出模拟的总体思路和具体实施方案以及在软件编写中注意的问题。我们将能更深入的理解“历法”这一中华民族特色的传统文化,更好的发挥历法在现代科学中的作用。对历法中算法的计算机模拟和复原研究额能会成为未来天文学史研究的趋势和热点问题。

猜你喜欢

枚举历法常数
从走马楼西汉简歧异干支谈汉初历法混用问题
基于理解性教学的信息技术教学案例研究
关于Landau常数和Euler-Mascheroni常数的渐近展开式以及Stirling级数的系数
发明新历法
数组在处理枚举无规律数据中的应用
历史上最长的一年
万有引力常数的测量
基于太阳影子定位枚举法模型的研究
基于枚举的并行排序与选择算法设计
紫外分光光度法测定曲札芪苷的解离常数