中 国 古 代 历 法 的 上 元 积 年 系 统

初稿: 2019年7月


自汉《三统历》以来至元《授时历》前,中国历法都是围绕上元积年编排的。翻开史书,叙述历法的第一句都是「上元某某以来,到某某年某某,积某某年」。陈遵妫在《中国天文学史》说:「一部中国历法史,几乎可以说是上元的演算史」。可见要深入了解中国古代历法,不可不识上元积年。本文根据数学家曲安京的《中国历法与数学》[1]和《中国数理天文学》[2]两书资料,简单叙述上元积年的起源,计算方法,如何用上元积年调整历法的天文常数,以及废除上元积年的原因。


内 容

  1. 引 言
  2. 上 元 积 年 的 推 算
    1. 概 述
    2. 同 余 方 程 组
    3. 同 余 方 程 组 有 解 的 充 要 条 件
    4. 演 纪 术
  3. 调 整 天 文 常 数
  4. 上 元 积 年 的 废 除
   参 考 文 献

引 言

从唐朝《大衍历》开始,历法的结构分成七个部分:气朔、发敛、日躔、晷漏、月离、交食、五星。气朔章讨论太阳和月亮的平均运动,发敛章讨论易卦、气候和置闰法,日躔章讨论太阳运动的不均匀及相关问题,晷漏章讨论晷影和漏刻的计算(即正午时晷影长度、太阳出没时刻、昏旦中星等),月离章讨论月亮运动的不均匀及相关问题,交食章讨论日食和月食的计算,五星章讨论水、金、火、木、土五行星的运行及算法。也就是说中国历法的内容很接近现代天文年历的内容。

中国古代的历法计算,往往是先订立一个起算点,称为历元。基本假设是天象是循环的,历元定于循环大周朔的起始时刻。初时历法的历元是假设其时是甲子日夜半(午夜零时),又是冬至和合朔时刻,称为朔旦冬至,这特殊时刻往往是推算出来的,而不是考察古天象的记录所得。到了西汉末年,刘歆用易经穿凿附会解释当时《太初历》的基本天文数据,使历法带有神秘色彩。他还提出「太极上元」这概念,不但要求甲子日朔旦冬至,而且还加了若干条件:岁的干支是甲子,又是交食周期的起点,木、火、土、金、水五行星同时会聚冬至点。刘歆将《太初历》更名为《三统历》,取太极上元到太初元年(公元前104年)为143127年。

现在我们说的天文学和占星术,古代无论在中国和西方都是不分开的,所以历法中常有占卜的内容,但是中国历法也和政治有密切关系。古代的天命论政治思想是君权天授,历朝都十分重视历法的制定和颁布,为了显示君主掌握天命,历法合天是十分重要的,这就是中国历法更改频繁的主要原因。刘歆故弄玄虚,使历法变得神秘,其中一个原因是为王莽篡汉提供天命论的理据。可是以后的历法家制定历法时,一律效法刘歆的做法推算上元,而且追求上元的理想条件不断提高。

后来的天文学家发现月亮在天空运行速度不均匀,称为月行迟疾,月行迟疾的周期就是现在所说的近点月。也发现月球通过黄道与白道的升交点又有不同的周期,即现代所说的交点月。月行迟疾和月亮过黄白交点的时刻对准确预测日食和月食都很重要,于是上元又加了近点月和交点月的周期,要求其时月行最速(或最慢),也就是月球过近(或远)地点的时刻,亦要求其时月亮过黄白的升(或降)交点。岁差的发现使恒星年这周期也加入上元的条件,上元要求冬至点正好位于北方之中虚宿之内。后来虽然又发现太阳运动不均匀(日行盈缩),但是历代都假设太阳在冬至运行最快,即假设近点年和回归年一致而且地球在冬至过近日点,这其实与事实不相符,但是古代的观测精度不足以察觉假设有误,因此日行盈缩没有影响上元的计算。所以理想的上元条件是某甲子年甲子日朔旦冬至,月球过近(远)地点与升(降)交点,木、火、土、金、水五行星同时会聚冬至点,而冬至点正好位于北方之中虚宿之内。

这样奇异的天象十分罕见,可以说是不存在的。历法家根据实测,定出了一组天文常数及日月五星的位置,用这些数据原则上可以推算上元。按照最理想的情形,推算上元涉及的天文常数有回归年、朔望月、恒星年、交点月、近点月、木、火、土、金、水五行星的会合周期,加上岁名和日名的干支周期,可以列出十一个联合一次同余方程组。其实古时也知道五星的运行有迟疾,理论上也要考虑五星过近日点的周期,不过由于古代对五星的近日点周期的观测数据比较粗糙,就不把这些周期列入同余方程组。

中国很早已经建立一套解同余方程组的方法,称为「大衍总术数」或「孙子定理」或「中国剩余定理」。这方法曾被学者认为就是古人推算上元积年的方法,但是这说法有两个严重问题。首先,用大衍总术数解这十一个同余方程组涉及的计算量十分庞大,不要说一千多年前的古代,即使以现代的计算水平,如果没有计算机的协助也是十分困难的。更重要的是这一方程组未必有解,如果同余方程组的被除数互质,方程保证有解,但是上元积年的同余方程组不满足这条件,因此方程组的余数必需满足某些条件才能保证有解,而大衍总术数没有机制判别方程有解的条件及如何处理无解的情况。还有一事令人费解:上元积年要满足这十一个同余方程必定是一个很大的数字,但是考查中国历代历法的上元积年数,除了南宋《淳佑历》和金朝杨级的《大明历》两部历法外,所有历法的上元积年不超过一亿年,此数如果确是解那十一个方程组的话就似嫌太小。那么历法家是如何计算上元积年的呢?

可惜的是自元朝《授时历》废除上元积年后,推算上元之法湮没不彰。明代以后,已经没有人知道传统历法的上元究竟是如何推算的。历法的颁布是皇权的象征,所以中国古代历法的制定原理是不公开的秘密,私习历法历来被视为违禁的行为。编制历法全是官办,历法的原理只在官方认可的很小范围内传播。二十四史中的天文律历志只是记载历法的推步方法,算法的构造原理是秘而不宣的。明朝制度规定历官皆世袭,而明朝《大统历》沿袭元朝的《授时历》,基本上无所作为。明成化(1465-1487)以后,日月食往往预报不准,但是世袭历官不学无术,对传统历法的编制机理已经不甚了了,以致朝廷研究改历时要求助西方传教士。

自清朝以来,已有学者探求古代历法的机理,并取得了不少成果,但是古人推算上元积年的方法一直是学界未解之谜,直到最近三十年才被数学家曲安京破解了这个失传几百年的算法。根据他的说法,不是每个周期都参与上元积年的推算。绝大多数的上元仅凭岁名、日名、回归年和朔望月四个周期确定,其他天文常数如近点月、交点月等以观测数据为参照,然后调整数值来配合算出的上元。上元积年其实隐含着一套制定天文常数的系统,详情在以下两节说明。


上 元 积 年 的 推 算概 述

根据曲安京的研究,历法家推算上元积年的步骤大致如下。首先调取合适的日法,所谓日法是指朔望月或回归年写成分数时的分母数字,例如东魏兴和历的朔望月定为6158017/208530日,208530就是兴和历的日法。回归年和朔望月当然是根据实测,但观测总会有误差,在误差范围内可以表示成不同的分数,所以可以调取不同的日法。有了回归年、朔望月和日法后就可以列出三个联合一次同余方程组,这样上元积年的计算只涉及岁名和日名的干支周期、回归年和朔望月。但是方程未必有解,如果无解或得出的上元积年数超过一亿年,就表明这组朔望月和回归年数据不合用,本轮计算无效,需要重新调取日法,选出另一组在观测的误差范围内可用的回归年和朔望月数据,再列同余算式求解,直到求出一个可用的上元积年为止。


同 余 方 程 组

中国历法往往以天正冬至作为一岁的起算点,所谓天正是指含冬至的月份,即建子月。由于中国自太初元年(前104年)后大多数以建寅为正月,天正冬至就是指上一年的十一月冬至。若用Ps表示回归年的日数,PL表示朔望月的日数,N表示某年与上元的积年数,R0表示该年与上一个甲子年的积年数,r1表示该年天正冬至与上一个甲子日夜半的日数,r2表示天正冬至与上一个合朔的日数(即天正冬至的月龄),则可以列出以下的同余方程组:

N≡R0 (mod 60), PsN≡r1 (mod 60), PsN≡r2 (mod PL)。   (1)

此处≡表示同余,最左边的方程是说(N-R0)是60的整数倍,中间的方程是说(PsN-r1)是60的整数倍,最右边的方程是说(PsN-r2)PL的整数倍。注意R0是整数,但是r1r2一般都不是整数,选取日法的目的是使上述同余方程组的数字化为整数。

唐朝《麟德历》以前的中国历法规定回归年和朔望月两者有特定的比例,历法的闰月因此有特定的周期,称为闰周。回归年和朔望月的最小公倍数称为章,一章所含的回归年数目称为章岁,一章所含的朔望月数目称为章月。例如《三统历》的章岁是19,章月是235,也就是说一章有19个回归年,也相当于235个朔望月,因为235=19×12+7,一章有七个闰月,所以《三统历》的闰月符合十九年七闰法的规律。如果把朔望月的日数写成PL=U/A,则回归年的日数是Ps=pU/(qA),此处U、A、p和q都是整数。A就是上面说的日法、p是章月、q是章岁。于是公式(1)可以写成:

N≡R0 (mod 60), pUN≡R1 (mod 60qA),pN≡R2 (mod q)。   (2)

其中R1=qAr1R2=qr2

如上述,早期历法取章岁19、章月235,南北朝开始打破传统。例如北凉《玄始历》取章岁600、章月7421(600年221闰),北魏《正光历》取章岁505、章月6246(505年186闰),祖冲之《大明历》取章岁391、章月4836(391年144闰),隋《开皇历》取章岁429、章月5306(429年158闰)等。到了唐朝,《麟德历》及以后的历法不再预设特定的闰周,回归年和朔望月都写成以日法A为分母的分数:Ps=T/APL=U/A,这里T、U和A都是整数。这样公式(1)可以写成:

N≡R0 (mod 60), TN≡R1 (mod 60A),TN≡R2 (mod U)。   (3)

其中R1=Ar1称为「气应」,R2=Ar2称为「闰应」。虽然不再预设闰周,但是闰周还是可以从T/AU/A的最小公倍数求得,只是《麟德历》及以后的历法都以定朔注历,所以闰周不再是闰月的周期。下面会说U、A和T可能要作调整使同余方程组有解,废除闰周前,只能调整U和A,废除闰周后,U、A和T都可自由调整,这就是两种方法在计算上元时的差异。


同 余 方 程 组 有 解 的 充 要 条 件

在解这些同余方程组前,应该先判别方程组是否有解,否则很可能会徒劳无功。这里用公式(3)的方程组说明。最左边方程的通解是N=R0+60m,而m是任意整数,把这通解代入中间的方程得

T(R0+60m)=R1+60An,

此处n是整数。这公式可写成

60g1(mt-na)=R1-TR0,   (4)

这里g1=gcd(T,A)是T和A的最大公约数,而t=T/g1a=A/g1,所以t和a互质。由于mt-na是整数,方程(4)有解的充要条件是60g1|(R1-TR0), 也就是说R1-TR0必需是60g1的整数倍。这个充要条件只是公式(3)左边两个方程有解的条件,并没有考虑最右边的方程,所以还有两个额外的充要条件。将通解N=R0+60m代入公式(3)最右边的方程,然后重复类似以上的运算可得方程有解的第二个充要条件:g2|(R2-R0T),其中g2=gcd(60T,U)。第三个充要条件可将公式(3)中间方程的通解代入最右边的方程推导出来,结果是:g3|(R1-R2),而g3=gcd(60A,U)。综合以上结果,同余方程组(3)有解的充要条件是:

60g1|(R1-TR0),g2|(R2-R0T)g3|(R1-R2)
g1=gcd(T,A),g2=gcd(60T,U)g3=gcd(60A,U)

如果条件不满足,就要调节R1=Ar1R2=Ar2的数值,r1r2由观测而得,所以不能调整太大,一般的原则是r1r2与观测值的偏差不能超过一刻。清朝以前是把一日分为一百刻,所以一刻是0.01日,即14.4分钟。如果在正负一刻范围内没有合用的R1R2使方程有解,则需要重新选取日法A,T和U也要重新选取使T/A和U/A与实测的回归年和朔望月的偏差在可接受的误差范围内,然后重新布列同余方程组,再检查是否能调出合用的R1R2,否则又要重新选取A、T和U重新计算,直至得出合用的R1R2为止。

上述的调整方法只是一个设想,历法家可能不是这样调整这些参数的,而是可能用演纪术边算边调参数。


演 纪 术

历家解这些方程组的方法是「演纪术」,此术很简单,这里仍以公式(3)的方程组为例说明。演纪术第一步是先解其中一条方程,这里就选最左边的方程,上面已求得方程的通解: N=R0+60m。第二步是将通解代入中间的方程,这在上面也已计算了,结果是公式(4),方程有解的充要条件是60g1|(R1-TR0),如果条件不满足就要调整R1,如果在可接受的范围内没有合用的R1,就要重新选取T、U和A。调好了R1后,公式(4)可以改写成:

mt-na=S1S1=(R1-TR0)/(60g1)
⇒  mt ≡ S1 (mod a)。

欲解此方程,首先是解μt≡1 (mod a),这可用大衍求一术计算,算出μ后乘S1便得m。注意m不是唯一的,将其中一解加上a的整数倍也是一解。用M表示正整数中的最小的一个解,则可将通解写成m=M+ka,其中k是任意整数,而N0=R0+60M就是上一次冬至发生在甲子年甲子日夜半与欲求之天正冬至的积年数,但是此时并非合朔,所以还得求出整数k使历元满足甲子年甲子日夜半朔旦冬至,这就要将通解N=R0+60(M+ka)代入公式(3)最右边的方程,结果是

TR0+60T(M+ka)=R2+Ub,b是整数,
⇒  60Tak-Ub=R2-TR0-60TM。

方程有解的充要条件是gcd(60Ta,U)|(R2-TR0-60TM),如果条件不满足,就要调整R2,如果在可接受的范围内没有合用的R2,就要重新选取T、U和A再重算。调好参数后可以把方程改写如下。

g=gcd(60Ta,U)v=60Ta/gu=U/gS3=(R2-TR0-60TM)/g,则得
vk-ub=S3 ⇒ vk≡S3 (mod u)

欲求k,先用大衍求一术解vz≡1 (mod u),然后把算出的z乘S3便得k,但是k不是唯一的,可以加上u的整数倍求出最小的正整数解,称之为K,那么上元积年N便是 N=R0+60(M+Ka)。如果求出的积年大于一亿年,则本轮计算无效,须要从新选取A、T和U直至得出N小于一亿的解为止。

简言之,演纪术的精义是先解一个方程,把通解代入第二个方程求解,然后再把通解代入第三个方程;而大衍总术数却是同时处理三个方程,涉及许多大数的连乘连除,计算量十分庞大,不及演纪术边算边化简,计算量比大衍总术数小很多倍。中国历法在后期所用的T、U和A都是很大的数字,演纪上元的简捷实用效果是非同小可的,而且演纪术提供了方程有解的条件,在计算时可以按情况调整参数。

求得一个合用的上元积年后,下一步是调整其他天文常数来配合这个上元,这就是下一节要讨论的问题。


调 整 天 文 常 数

求出了上元积年后,就要调整其他天文常数配合既定的上元。这是因为上元不单止是朔旦冬至,亦是月球过近(远)地点、过升(降)交点及五星会聚之时刻,但是相关的周期都没有参与上元的推算,算出的上元当然不能符合实测数据,所以必需调整这些周期。现在以近点月为例说明如何调整数据。

首先引入两个函数:floor(x)表示不大于x的最大整数,
mod(X,Y)=X-Y·loor(X/Y)是X除以Y后所得之余数。

假设某历法推出某年冬至的上元积年数是一万年,又假设这部历法的回归年取(365+97/400)日=365.2425日。假设观测得出在冬至时月球过了近地点已有12.3457日,而近点月的实测值是27.5546日。这个上元是否符合观测数据?上元积年一万年,就是说这冬至距上元积日3652425日,如果假设月球在上元过近地点,近点月是27.5546日,则这冬至距上一次月球过近地点有mod(3652425,27.5546)日=7.6608日,显然不符合观测值。所以必需将近点月的数值改为Pa,使得mod(3652425,Pa)=12.3457,其解是要求3652425-12.3457是Pa的整数倍,由此得出Pa=3652412.6543/n,而n是任何大于0的整数。当然Pa越接近实测数值越好,如果取Pa=27.5546,则n=3652412.6543/27.5546=132551.83显然不是整数,取最接近的整数132552得Pa=3652412.6543/132552=27.55456465613495,比实测值只是小了三秒。古代的观测精度没有这么高,取这个数值不会损害历法的精度,只是这个Pa并非简单分数,计算时不方便,一般会选取另一个Pa既能符合实测数据,又能表示成较为简单的分数。上元积年的数值越大,就越容易找到适合的分数既能符合观测数据,又能附会既定的上元。

现代天文学的常数系统可分为定义常数(defining constants),初始常数(primary constants)和推导常数(derived constants)等。顾名思义,定义常数是根据定义而制定的常数,例如光速299792458米/秒就是定义常数,一米的长度就是定义为光在一秒钟所走距离的299792458分之一。初始常数是由观测而定的常数,例如地球赤道半径。推导常数是由初始常数或定义常数推导出的常数,例如太阳与地球的质量比。以现代天文学的观念来说,用既定上元来定出的天文常数就是推导常数,所以在上元这套历法系统,恒星年、交点月、近点月、五星会合周期等都是推导常数。这说法看似不妥,因为我们认为这些常数应是靠观测而定,而不应是推导出来的。但是在上元这套系统中,这些常数的实测值只是参考值,历法采用的数值是为了附会上元而推出的数值,只是在「推导」过程中不能使数值太偏离实测值,否则历法不能与天象相符。

虽然古代大部分的历法都是调整天文常数附会上元,也有人不赞同这做法,例如杜预在其《春秋长历》说:「《书》所谓『钦若昊天,历象日月星辰』,《易》所谓『治历明时』,言当顺天以求合,非为合以验天也。」「顺天以求合」,是指用实测数据直接推算天象;「为合以验天」,指以实测数据为参照,调整选择与之相近的历法数据来配合既定的上元。由于日月食的推算要从上元算起,故需要「为合以验天」。杨伟制《景初历》(237年),破天荒取交食周期及近点月周期的起点游离于上元之外,从而大幅度提高了近点月的精度。南北朝何承天的《元嘉历》(443年),将五星会合周期各立「后元」,大大提高了五星会合周期的精度。何承天也赞同治历应「顺天以求合」。但是何承天的做法遭受非议,以后的历家仍继续调整天文常数附会上元。

上面的例子说明了如果上元积年足够大,是可以比较容易找到合用的数值既可附会上元,亦可接近观测数据。但是上元积年数大使计算不方便,所以必须有所取舍,历代大多以一亿年为上元积年的上限。由于观测精度的提高,这限制使历法的精度无法提高,最终导致上元积年的废除。


上 元 积 年 的 废 除

上元系统的最大弊病是计算复杂,这系统不但在历法的制定和计算上无甚帮助,反而阻碍历法的改良,最终在元朝《授时历》被废除。李谦应召作《授时历议》,说明《授时历》的进步,同时「考证前代人为附会之失」:

历法之作,所以步日月之躔离,候气朔之盈虚,不揆其端,无以测知天道,而与之吻合。然日月之行迟速不同,气朔之运参差不一,昔人立法,必推求往古生数之始,谓之演纪上元。当斯之际,日月五星同度,如合璧连珠然。惟其世代绵远,驯积其数至逾亿万,后人厌其布算繁多,互相推考,断截其数而增损日法,以为得改宪之术,此历代积年日法所以不能相同者也。然行之未远,浸复差失,盖天道自然,岂人为附会所能苟合哉。夫七政运行于天,进退自有常度,苟原始要终,候验周匝,则象数昭著,有不容隐者,又何必舍目前简易之法,而求亿万年宏阔之术哉。

   —《元史‧历志》卷五十三,《历代天文律历等志汇编》(九),三三五七页。

由于观测精度提高,能选的日法也变得大,同余方程组解出的积年数达到亿万并不少见。治历者对于大于亿年的积年数在布算或附会的过程中感到不便,要求大于一亿的积年不合用,于是多次调整日法,反复推考,「断截其数」以得出合用的积年。但是过了不久就发现与天象不符(「行之未远,浸复差失」),于是又要修改历法重新推算上元积年。两宋三百多年间用了十九部历法,平均十七年就要改一次历法,一方面说明了观测的进步,历法的误差很容易被发现,另一方面说明历法并没有大改良,其中原因很可能就是历法被上元系统束缚着。滑稽的是,这些历法的开首术文虽然云:「上元至今积若干千万年」,但是实际上过了二十年左右已发现不合天。元朝的《授时历》于1281年颁行,用至元朝灭亡,明朝建立后,更名为《大统历》,用至明末。除了微小修改外,《大统历》基本上沿袭《授时历》,所以《授时历》可以说在中国用了超过360年。《授时历》之精湛,除了废上元积年外,还因为当时改良了天文仪器,使测验精度大为提高,在理论推算上也集历代诸家之大成。



参 考 文 献