tidy and re-organize code, add more comments

This commit is contained in:
Chen Wei
2016-04-14 19:52:36 +08:00
parent 504a0a27ba
commit f2dd3cacc4
2 changed files with 166 additions and 106 deletions

View File

@@ -1,5 +1,6 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#include <math.h> #include <math.h>
#include <time.h> #include <time.h>
#include "astro.h" #include "astro.h"
@@ -17,10 +18,10 @@ static char *CN_MON[] = {
"十二月", "十二月",
"正月", "二月", "三月", "四月", "五月", "六月", "正月", "二月", "三月", "四月", "五月", "六月",
"七月", "八月", "九月", "十月", "十一月", "十二月", /* index = 12 */ "七月", "八月", "九月", "十月", "十一月", "十二月", /* index = 12 */
"", "", "", "", "", "", /* pad from index 13 to 18 */ "", "", "", "", "", "", "", /* pad from index 13 to 19 */
"閏十一月", "閏十二月", "閏正月", "閏二月", "閏三月", "閏四月", "閏十二月", "閏正月", "閏二月", "閏三月", "閏四月", "閏五月",
"五月", "六月", "閏七月", "閏八月", "閏九月", "閏十月", "閏六月", "閏七月", "閏八月", "閏九月", "閏十月", "閏十一月",
"閏十一月", "閏十二月" "閏十二月"
}; };
/* solar term's angle + 120 / 15 */ /* solar term's angle + 120 / 15 */
@@ -51,8 +52,8 @@ static char *CN_HOLIDAY[] = {
}; };
static double newmoons[MAX_NEWMOONS]; static double newmoons[MAX_NEWMOONS];
static double solarterms[MAX_SOLARTERMS]; static struct solarterm solarterms[MAX_SOLARTERMS];
static int firstnm_offset; static int nm_before_ws_index;
static struct lunarcal_cache *cached_lcs[CACHESIZE]; static struct lunarcal_cache *cached_lcs[CACHESIZE];
static int cache_initialized = 0; /* flag for initialized cache */ static int cache_initialized = 0; /* flag for initialized cache */
@@ -88,6 +89,7 @@ void init_cache(void)
struct lunarcal_cache *tmp; struct lunarcal_cache *tmp;
for (i = 0; i < CACHESIZE; i++) { for (i = 0; i < CACHESIZE; i++) {
tmp = (struct lunarcal_cache *) malloc(sizeof(struct lunarcal_cache)); tmp = (struct lunarcal_cache *) malloc(sizeof(struct lunarcal_cache));
memset(tmp, 0, sizeof(struct lunarcal_cache));
tmp->year = -1; tmp->year = -1;
tmp->len = -1; tmp->len = -1;
cached_lcs[i] = tmp; cached_lcs[i] = tmp;
@@ -95,6 +97,7 @@ void init_cache(void)
cache_initialized = 1; cache_initialized = 1;
} }
void cn_lunarcal(int year) void cn_lunarcal(int year)
{ {
int i, k, len1, len2; int i, k, len1, len2;
@@ -102,25 +105,37 @@ void cn_lunarcal(int year)
struct lunarcal *thisyear[MAX_DAYS]; struct lunarcal *thisyear[MAX_DAYS];
struct lunarcal *nextyear[MAX_DAYS]; struct lunarcal *nextyear[MAX_DAYS];
struct lunarcal *output[MAX_DAYS]; struct lunarcal *output[MAX_DAYS];
init_cache();
len1 = get_cached_lc(thisyear, year);
len2 = get_cached_lc(nextyear, year + 1);
/* combine lunar calendars from this and next year. Leapmonth close to the init_cache();
* end of Gregorian year can only be found by compute Lunar calendar of the len1 = get_cached_lc(thisyear, MAX_DAYS, year);
* next year */ len2 = get_cached_lc(nextyear, MAX_DAYS, year + 1);
/*
* Luncar calendar calculated above starts at Lunar calendar month 11, day
* 1 of previous Gregorian year. Because Leapmonth close to the end of
* Gregorian year can only be found by compute Lunar calendar of the next
* year, merge lunar calendars from this and next year results the lunar
* calendar for this Gregorian year.
*/
ystart = g2jd(year, 1, 1.0); ystart = g2jd(year, 1, 1.0);
yend = g2jd(year, 12, 31.0); yend = g2jd(year, 12, 31.0);
k = 0; k = 0;
/*
* lunar calendar after this lunar calendar month 11, day 1 shall come from
* lc of next year
*/
for (i = 0; i < len1; i++) { for (i = 0; i < len1; i++) {
if (thisyear[i]->jd == nextyear[0]->jd)
break;
if (thisyear[i]->jd >= ystart) if (thisyear[i]->jd >= ystart)
output[k++] = thisyear[i]; output[k++] = thisyear[i];
} }
for (i = 0; i < len2; i++) {
if (nextyear[i]->jd <= yend) for (i = 0; k < MAX_DAYS && i < len2 && nextyear[i]->jd <= yend; k++, i++)
output[k++] = nextyear[i]; output[k] = nextyear[i];
}
print_lunarcal(output, k); print_lunarcal(output, k);
} }
@@ -129,34 +144,41 @@ void cn_lunarcal(int year)
int get_cache_index(int year) int get_cache_index(int year)
{ {
int i; int i;
for (i = 0; i < CACHESIZE; i++) {
for (i = 0; i < CACHESIZE; i++)
if (cached_lcs[i]->year == year) if (cached_lcs[i]->year == year)
return i; return i;
}
return -1; return -1;
} }
int get_cached_lc(struct lunarcal *p[], int year) int get_cached_lc(struct lunarcal *lcs[], int len, int year)
{ {
int i, k, len; int i, k, lc_days;
double angle;
double jd_nm, est_nm; double jd_nm, est_nm;
int angle;
int start_solarterm_lon = -120; /* 小雪 of last year */
if ((k = get_cache_index(year)) > -1) { for (i = 0; i < len; i++)
for (i = 0; i < cached_lcs[k]->len; i++) { lcs[i] = NULL;
p[i] = cached_lcs[k]->lcs[i];
} if ((k = get_cache_index(year)) != -1) {
return i; for (i = 0; i < cached_lcs[k]->len; i++)
lcs[i] = cached_lcs[k]->lcs[i];
return cached_lcs[k]->len;
} }
/* search solar terms start from 小雪 of last year */
for (i = 0; i < MAX_SOLARTERMS; i++) { for (i = 0; i < MAX_SOLARTERMS; i++) {
angle = (double) (i * 15 - 120); angle = start_solarterm_lon + i * 15;
solarterms[i] = normjd(solarterm(year, angle), TZ_CN); solarterms[i].longitude = angle;
solarterms[i].jd = normjd(solarterm(year, (double) angle), TZ_CN);
} }
/* search 15 newmoons start 30 days before last Winter Solstice */ /* search 15 newmoons start 30 days before last Winter Solstice */
est_nm = solarterms[2] - 30; est_nm = solarterms[2].jd - 30;
for (i = 0; i < MAX_NEWMOONS; i++) { for (i = 0; i < MAX_NEWMOONS; i++) {
jd_nm = newmoon(est_nm); jd_nm = newmoon(est_nm);
newmoons[i] = normjd(jd_nm, TZ_CN); newmoons[i] = normjd(jd_nm, TZ_CN);
@@ -164,10 +186,10 @@ int get_cached_lc(struct lunarcal *p[], int year)
} }
/* fill in and mark each day with its lunar calendar year, month, day */ /* fill in and mark each day with its lunar calendar year, month, day */
len = mark_month_day(p); lc_days = mark_month_day(lcs, len);
/* mark Traditional Chinese holiday */ /* mark Traditional Chinese holiday */
mark_holiday(p, len); mark_holiday(lcs, lc_days);
/* add to cache */ /* add to cache */
if (cachep >= CACHESIZE) { if (cachep >= CACHESIZE) {
@@ -181,67 +203,69 @@ int get_cached_lc(struct lunarcal *p[], int year)
} }
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
cached_lcs[cachep]->lcs[i] = p[i]; cached_lcs[cachep]->lcs[i] = lcs[i];
} }
cached_lcs[cachep]->year = year; cached_lcs[cachep]->year = year;
cached_lcs[cachep]->len = len; cached_lcs[cachep]->len = lc_days;
cachep++; cachep++;
return len; return lc_days;
} }
/* mark month and day number, solarterms */ /* mark month and day number, solarterms */
int mark_month_day(struct lunarcal *lcs[]) int mark_month_day(struct lunarcal *lcs[], int len)
{ {
int i, k, len, idx_lc_newyear; int i, k, n, lc_newyear;
int leapmonth, month; int leapmonth, month, month_days;
double lc_start, lc_end, jd, month_day1; double lc_november1st, end, jd;
struct lunarcal *lc; struct lunarcal *lc;
GregorianDate g; GregorianDate g;
len = 0; n = 0;
month = 11; month = 11;
month_day1 = 0; month_days = 0;
idx_lc_newyear = -1; lc_newyear = -1;
leapmonth = find_leap(); leapmonth = find_leap();
lc_start = newmoons[firstnm_offset]; lc_november1st = newmoons[nm_before_ws_index];
lc_end = solarterms[MAX_SOLARTERMS -1]; end = solarterms[MAX_SOLARTERMS - 1].jd;
jd = lc_start;
while (jd < lc_end) { /* fill in days into array lcs */ /* start from month 11 of previous lunar calendar year */
/* scan for month jd belongs */ int cur_nm = nm_before_ws_index;
for (i = firstnm_offset; i < MAX_NEWMOONS; i++) { jd = lc_november1st;
if (jd < newmoons[i]) { while (jd < end && cur_nm < MAX_NEWMOONS - 1) {
month = 11 + i - 1 - firstnm_offset; /* the lunar calendar month jd belongs */
month_day1 = newmoons[i - 1]; month = 11 + cur_nm - nm_before_ws_index;
break; month_days = (int) newmoons[cur_nm + 1] - newmoons[cur_nm] + 1;
}
}
/* adjust leapmonth */ /* adjust leapmonth */
if (leapmonth > -1 && month == leapmonth) { if (leapmonth != -1 && month == leapmonth)
month = (month - 1) % 12 + 20; /* add offset 20 to distinguish */ month = (month - 1) % 12 + 20; /* add offset 20 to distinguish */
} else if (leapmonth > -1 && month > leapmonth) { else if (leapmonth != -1 && month > leapmonth)
month = (month - 1) % 12; month = (month - 1) % 12;
} else { else
month %= 12; month %= 12;
if (month == 1)
lc_newyear = n; /* found 正月初一 */
for (i = 0; i < month_days; i++) {
lc = lcalloc(jd);
lc->month = month;
lc->day = i + 1;
lcs[n++] = lc;
jd += 1.0;
} }
lc = lcalloc(jd); cur_nm++;
lc->month = month;
lc->day = (int) (jd - month_day1 + 1);
if (lc->month == 1 && lc->day == 1)
idx_lc_newyear = len; /* found 正月初一 */
lcs[len++] = lc;
jd += 1.0;
} }
/* mark lunar year */ /* mark lunar year */
int lyear; int lyear;
g = jd2g(lcs[idx_lc_newyear]->jd); /* 正月初一 in Gregorian */ g = jd2g(lcs[lc_newyear]->jd); /* 正月初一 in Gregorian */
for (i = 0; i < len; i++) { for (i = 0; i < n; i++) {
if (i < idx_lc_newyear) if (i < lc_newyear)
lyear = g.year - 1; lyear = g.year - 1;
else else
lyear = g.year; lyear = g.year;
@@ -249,19 +273,21 @@ int mark_month_day(struct lunarcal *lcs[])
lcs[i]->lyear = lyear; lcs[i]->lyear = lyear;
} }
/* modify days with solar terms */ /* mark solarterms */
for (i = 0; i < MAX_SOLARTERMS - 1; i++) { for (i = 0; i < MAX_SOLARTERMS - 1; i++) {
if (solarterms[i] >= lc_start) { if (solarterms[i].jd >= lc_november1st) {
k = (int) (solarterms[i] - lc_start); k = (int) (solarterms[i].jd - lc_november1st);
if (lcs[k]) if (lcs[k])
lcs[k]->solarterm = i; lcs[k]->solarterm = i;
} }
} }
return len;
return n;
} }
/* mark traditional chinese holiday /*
* mark traditional chinese holiday
* *
* 腊八节(腊月初八) 除夕(腊月的最后一天) 春节(一月一日) * 腊八节(腊月初八) 除夕(腊月的最后一天) 春节(一月一日)
* 元宵节(一月十五日) 寒食节(清明的前一天) 端午节(五月初五) * 元宵节(一月十五日) 寒食节(清明的前一天) 端午节(五月初五)
@@ -275,23 +301,27 @@ void mark_holiday(struct lunarcal *lcs[], int len)
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
lc = lcs[i]; lc = lcs[i];
if (lc->month == 12 && lc->day == 8) { if (lc->month == 0 && lc->day == 8) {
lc->holiday = 0; /* 腊八 index into CN_HOLIDAY */ lc->holiday = 0; /* 腊八 index into CN_HOLIDAY */
i += 15; /* fastforward */
} else if (lc->month == 1 && lc->day == 1) { } else if (lc->month == 1 && lc->day == 1) {
lcs[i - 1]->holiday = 1; /* 除夕 */ lcs[i - 1]->holiday = 1; /* 除夕 */
lc->holiday = 2; /* 春节 */ lc->holiday = 2; /* 春节 */
} else if (lc->month == 1 && lc->day == 15) { lcs[i + 14]->holiday = 3; /* 元宵 */
lc->holiday = 3; /* 元宵 */ i += 20; /* fastforward to 清明 */
} else if (lc->month == 5 && lc->day == 5) { } else if (lc->month == 5 && lc->day == 5) {
lc->holiday = 5; /* 端午 */ lc->holiday = 5; /* 端午 */
i += 2 * 27;
} else if (lc->month == 7 && lc->day == 7) { } else if (lc->month == 7 && lc->day == 7) {
lc->holiday = 6; /* 七夕 */ lc->holiday = 6; /* 七夕 */
} else if (lc->month == 7 && lc->day == 15) { lcs[i + 8]->holiday = 7; /* 中元 */
lc->holiday = 7; /* 中元 */ i += 27;
} else if (lc->month == 8 && lc->day == 15) { } else if (lc->month == 8 && lc->day == 15) {
lc->holiday = 8; /* 中秋 */ lc->holiday = 8; /* 中秋 */
i += 20;
} else if (lc->month == 9 && lc->day == 9) { } else if (lc->month == 9 && lc->day == 9) {
lc->holiday = 9; /* 重阳 */ lc->holiday = 9; /* 重阳 */
i += 27;
} else if (lc->month == 10 && lc->day == 15) { } else if (lc->month == 10 && lc->day == 15) {
lc->holiday = 10; /* 下元 */ lc->holiday = 10; /* 下元 */
break; break;
@@ -303,51 +333,75 @@ void mark_holiday(struct lunarcal *lcs[], int len)
} }
/*
* find last newmoon before Winter Solstic and determin the leapmonth
*
* Return: -1 if not a leap year
* values other than -1 indicate leapmonth, count from 11,
* 12 for leap lc month 11,
* 13 for leap lc month 12,
* 14 for leap lc month 1,
* ...
*/
int find_leap(void) int find_leap(void)
{ {
/* count newmoons between two Winter Solstice */ int nmcount, found_leap, leapmonth, i, n;
int nmcount, flag, leapmonth, i, n; double first_winter_solstice = solarterms[2].jd;
nmcount = 0; double second_winter_solstice = solarterms[26].jd;
for (i = 0; i < MAX_NEWMOONS; i++) {
if (newmoons[i] > solarterms[2]
&& newmoons[i] <= solarterms[MAX_SOLARTERMS - 1])
nmcount += 1;
}
/* first new moon of new year */ /*
* find the last new moon before first Winter Solstic
* the lunar calendar month that Winter Solstic belongs is always month 11,
*/
for (i = 0; i < MAX_NEWMOONS; i++) { for (i = 0; i < MAX_NEWMOONS; i++) {
if (newmoons[i] > solarterms[2]) { if (newmoons[i] > first_winter_solstice) {
firstnm_offset = i - 1; nm_before_ws_index = i - 1;
break; break;
} }
} }
/* count newmoons between two Winter Solstice */
nmcount = 0;
for (i = 0; i < MAX_NEWMOONS; i++) {
if (newmoons[i] > first_winter_solstice &&
newmoons[i] <= second_winter_solstice)
nmcount += 1;
}
/* leap year has more than 12 newmoons between two Winter Solstice */ /* leap year has more than 12 newmoons between two Winter Solstice */
if (nmcount > 12) { leapmonth = -1;
for (i = 1; i < MAX_NEWMOONS; i++) { if (nmcount <= 12)
flag = 0; return leapmonth;
for (n = 0; n < MAX_SOLARTERMS; n++) {
/* the leap month is the first month which does NOT contain /*
* solar terms that is multiple of 30 degrees */ * the leap month is the first lunar calendar month which does NOT contain
if (solarterms[n] >= newmoons[i - 1] * solar terms that is multiple of 30 degrees
&& solarterms[n] < newmoons[i] */
&& n % 2 == 0) for (i = 0; i < MAX_NEWMOONS - 1; i++) {
flag = 1; found_leap = 1;
} for (n = 0; n < MAX_SOLARTERMS; n++) {
if (!flag) { if (solarterms[n].jd >= newmoons[i + 1])
leapmonth = 11 + i - 1 - firstnm_offset; break;
return leapmonth;
} if (solarterms[n].jd >= newmoons[i] &&
solarterms[n].longitude % 30 == 0)
found_leap = 0;
}
if (found_leap) {
leapmonth = 11 + i - nm_before_ws_index;
break;
} }
} }
return -1; return leapmonth;
} }
struct lunarcal *lcalloc(double jd) struct lunarcal *lcalloc(double jd)
{ {
struct lunarcal *p; struct lunarcal *p;
p = (struct lunarcal *) malloc(sizeof(struct lunarcal)); p = (struct lunarcal *) malloc(sizeof(struct lunarcal));
if (p) { if (p) {
p->jd = jd; p->jd = jd;
@@ -357,6 +411,7 @@ struct lunarcal *lcalloc(double jd)
p->day = -1; p->day = -1;
p->holiday = -1; p->holiday = -1;
} }
return p; return p;
} }

View File

@@ -4,6 +4,11 @@
#define CACHESIZE 3 #define CACHESIZE 3
#define TZ_CN 8 #define TZ_CN 8
struct solarterm {
double jd;
int longitude;
};
struct lunarcal { struct lunarcal {
double jd; double jd;
int solarterm; /* index of solarterm */ int solarterm; /* index of solarterm */
@@ -22,13 +27,13 @@ struct lunarcal_cache { /* the item in cache */
/* Function prototypes */ /* Function prototypes */
void cn_lunarcal(int year); void cn_lunarcal(int year);
int get_cached_lc(struct lunarcal *p[], int year); int get_cached_lc(struct lunarcal *lcs[], int len, int year);
double normjd(double jd, double tz); double normjd(double jd, double tz);
int find_leap(void); int find_leap(void);
int mark_month_day(struct lunarcal *lcs[]); int mark_month_day(struct lunarcal *lcs[], int len);
void ganzhi(char *buf, size_t buflen, int lyear); void ganzhi(char *buf, size_t buflen, int lyear);