四分历基本算法

(97) 2024-04-10 11:01:01

以历术甲子篇为例,通过修改数据可以得到其他历法的历表,基本求算方法不变。

完整程序及求算结果,请参见《历术甲子篇》冬至合朔表_甲子蔀塑闰表-CSDN博客

及CSDN

1. 基本常数

四分历:岁实365又1/4,朔策29又499/940。蔀日27759,蔀月940,一蔀76年,一章19年235月亦228气。

干支表:

 0 甲子      1 乙丑      2 丙寅      3 丁卯      4 戊辰      5 己巳      6 庚午      7 辛未      8 壬申      9 癸酉    
10 甲戌    11 乙亥    12 丙子    13 丁丑    14 戊寅    15 己卯    16 庚辰    17 辛巳    18 壬午    19 癸未    
20 甲申    21 乙酉    22 丙戌    23 丁亥    24 戊子    25 己丑    26 庚寅    27 辛卯    28 壬辰    29 癸巳    
30 甲午    31 乙未    32 丙申    33 丁酉    34 戊戌    35 己亥    36 庚子    37 辛丑    38 壬寅    39 癸卯    
40 甲辰    41 乙巳    42 丙午    43 丁未    44 戊申    45 己酉    46 庚戌    47 辛亥    48 壬子    49 癸丑    
50 甲寅    51 乙卯    52 丙辰    53 丁巳    54 戊午    55 己未    56 庚申    57 辛酉    58 壬戌    59 癸亥    

2. 历元

要求回归年的历元冬至点刚好在冬至所在月合朔皆在夜半0时,且在干支纪日的首日,即“十一月甲子夜半朔旦冬至”。如殷历以BC1567年为历元,近距为BC427年,岁在甲寅,称甲寅元。

3. 大小余

古代以干支纪日,需求朔日干支,若以初值0为甲子,每60一循环,即可以对60求余,第二年冬至月朔日余54又348/940,其中54称为大余,348称为小余,940称为日法或蔀月。任意一年冬至月朔的表达式即为:

四分历基本算法 (https://mushiming.com/)  第1张

由公式可知,求大余即使用整除运算符,求小余即使用求余运算符。其中蔀日/日法即为太阴年长度354又499/940。

(1) 冬至月朔

四分历每蔀蔀首的冬至点与冬至所在月的合朔时刻同在夜半,以此为起点,求一蔀内任意一年的正月朔,只需根据该朔日距离蔀首的日数(积日),再对60求余,得到该日的干支序号。

rbn = ryn % bf #入蔀年
jy = int(rbn*235/19) #积月
sddy_0 = jy * br // by % 60
sdxy_0 = jy * br % by

(2)任意月朔

历法推算的基本求算方法是积余法,已知初值,加上步长即可得任意一天的值。如某年冬至月的朔日为0,则第二月的朔日为29又499/940,若该年不闰,则第二年冬至月朔日为累加12次朔策(即将函数迭代12次),得354又348/940。

def qy(dy_0, xy_0, rf, dy, xy, n=1):  # 求大小余分(余分前值,日法,余分)
	zf = (dy_0 * rf + xy_0) + (dy * rf + xy) * n
	dy = (zf // rf) % 60
	xy = zf % rf
	return dy, xy

(3)合朔时刻

某月的合朔时间即该月的小余与日法的比值。历元无小余即0时合朔,第二年小余348,即合朔时间为348/940*24h,再由小数表示转换为时刻表示。同样只需对基本算法进行递归,即可输出每年年前冬至所在月的合朔时间。

def heshuo(yf,rf): #求合朔时间(余分,日法)
    chen = yf / rf * 24  # 合朔时间
    chen_h = int(chen)
    chen_m = int((chen - chen_h) * 60)
    chen_s = int(chen*3600 - chen_h*3600 - chen_m * 60)
    hssj = "{:02d}时{:02d}分{:02d}秒".format(chen_h,chen_m,chen_s)
    return hssj

4. 冬至

两次冬至的间隔时间即是一个回归年,古称岁实。

计算任意一年的冬至大小余,即求出该年距离蔀首的积日,再对60取余。公式类同朔旦大小余。

rbn = rjn % bf #入蔀年
jq = rbn * 12  # 积气
zqdy_0 = jq * 974 // 32 % 60
zqxy_0 = jq * 974 % 32

5.节气

四分历使用平气法,只需将一年平分为12节气和12中气,则气策为15又7/32日,两次中气间隔30又14/32日。利用求余函数,只需知道第一个节气的值,即可求出每一个节气的值。

6. 闰法

(1)闰余法

每章(19年)回归年共235月,太阴年共228月,则每年回归年较太阴年长7/19月,即每年闰余为7。积累至19(19/19月)则需置闰,此即闰年。置闰之后需减去19才是下一年闰余。

    if ry >= 19:     #置闰方法:闰余法
        sddy_0,sdxy_0 = qy(sddy_0,sdxy_0,sdrf,sddy+int(yue),sdxy+499) #加一个闰月
        ry -= 19
    else:
        sddy_0,sdxy_0 = qy(sddy_0,sdxy_0,sdrf,sddy,sdxy)
    ry += 7

由每年闰余7/19得每月闰余7/228月,求闰月,即以闰年年前闰余为初值(余分乘以12),每月加7/228,积累至228/228,即需置闰,此即闰月。

ry = 0
for i in range(n): # 年
    if ry >= 12: # 有闰年
        yry = ry * 12
        zry = int((228 - yry) // 7)
        month = '闰' + yuefen[(zry - 1) % 12]
    ry += 7  # 岁末闰余

(2)无中气置闰法

即每章(19年)共7闰,则章月235,每年中气12,则章气228。19年中必然有7个月没有中气,以此无中气月为闰月。求算方法是:若某月上月中气干支序号加中气间隔日期减去该月朔日干支序号的值大于或等于该月日数,则表示下一中气需要排到下月中(即该月无中气)。

def wzqy(dy_0,xy_0): #无中气月
	global zqdy_0,zqxy_0,yueri_0,yueri
	if dxy(yxy_0) == "大": yueri = 30
	else:yueri = 29
	if (int(dy_0+xy_0/32+zqi)-ydy_0)%60>=yueri:  #上一个中气值加中气日数即预推下一个中气的值,下一中气不在该月中则该月无中气
		x = True
		return x,dy_0,xy_0
	else:
		dy_0, xy_0 = qy(dy_0, xy_0, zqrf, zqdy, zqxy)
		x = False
		return x,dy_0,xy_0

(2)年终置闰法

年终置闰法则比较简单,在有闰之年的年末加一月即可。

THE END

发表回复