《Numerical Recipes》给的第一个程序是计算月相、儒略日和普通日之间的互相转换这样的。但貌似以前都居然不知道有儒略日这个东西,这样太伤我心了。查一下:
儒略日是啥呢?
儒略日一种不用年和月却只用日的纪年法。它的起点,也就是(儒略日=0)那天是B.C.4713年1月1日12:00到B.C.4713年1月2日12:00(格林威治时间)
对于计算机的好处就是它可以直接用int储存。
书中的第一个例程是void flmoon(const int n, const int phase, int * const julian_day, double * const frac);
它的作用是传递给它n和phase作为输入,其中phase是你想要计算的月相,n是让它计算出(从1900.01开始的)第n个phase月相的儒略日。
julian_day作为儒略日的输出,frac是那天的一个校准值,可以得到什么时候出现的那种月相,也就是几点几分这样的。
比较悲剧的是,它并没有告诉我解释公式是怎么回事,也不告诉我它是怎么做到的。大家先来看一下:
/** *@file calendar.h */ #ifndef CALENDAR_H_INCLUDED #define CALENDAR_H_INCLUDED /** *@brief This routine calculates the phases of the moon. *@param n Input for n-th such phase to be calculated *@param phase Input for the phase to be calculated (phase = 0 for new moon, 1 for first quarter, 2 for full, 3 for last quarter) *@param julian_day Output the Julian Day Number of that day *@param frac Output the fractional part of that day *Introduction: *Given an integer n and a code phase for the phase desired *(phase = 0 for new moon, 1 for first quarter, 2 for full, 3 for last quarter), *the routine returns the Julian Day Number julian_day, and the fractional part of a day frac to be *added to it, of the n-th such phase since January, 1900. Greenwich Mean Time is assumed. */ void flmoon(const int n, const int phase, int * const julian_day, double * const frac){ const double RAD = 3.141592653589793238/180.0; int i; double am, as, c, t, t2, xtra; c = n + phase/4.0; t = c/1236.85; t2 = t*t; as = 359.2242 + 29.105356 * c; am = 306.0253 + 385.816918 * c + 0.010730 * t2; *julian_day = 2415020 + 28 * n + 7 * phase; xtra = 0.75933 + 1.53058868 * c + ((1.178e-4)-(1.55e-7) * t) * t2; if(phase == 0 || phase == 2) xtra += (0.1734 - 3.93e-4 * t) * sin(RAD * as) - 0.4068 * sin(RAD * am); else if(phase == 1 || phase == 3) xtra += (0.1721 - 4.0e-4 * t) * sin(RAD * as) - 0.6280 * sin(RAD * am); else printf("phase is unknown in flmoon\n"); i = (int)(xtra >= 0.0 ? floor(xtra) : ceil(xtra - 1.0)); *julian_day += i; *frac = xtra - i; }
第二个例程是int julday(const int month, const int day, const int year);
它的作用是把普通的日期转换到儒略日去。
值得一提的是,数字365.25是四年一闰年的平均每年有的天数,但30.6001却让我难以理解、缺少指明性。根据第二个参考链接,可能与月份的计数方式与蔡勒公式相同所致。
/** *@brief Convert calendar date into Julian Day Number *@param month the month of the calendar date *@param day the day of the calendar date *@param year the year of the calendar date *@return the corresponding Julian Day *In this routine julday returns the Julian Day Number that begins *at noon of the calendar date specified by month, day, and year, *all integer variables. Positive year signifies A.D.; negative, B.C. *@attention Remember that the year after 1 B.C. was 1 A.D. */ int julday(const int month, const int day, const int year){ const int IGREG = 15+31*(10+12*1582); //Gregorian Calendat adopted Oct. 15, 1582. int ja, jul, jy = year, jm; if(jy == 0) printf("julday: there is no year zero."); if(jy < 0) ++jy; if(month > 2){ jm = month+1; } else{ --jy; jm = month+13; } jul = (int)(floor(365.25*jy) + floor(30.6001*jm) + day + 1720995); if(day + 31*(month+12*year) >= IGREG){ //Test whether to change to Gregorian Calendar ja = (int)(0.01*jy); jul += 2 - ja + (int)(0.25*ja); } return jul; }
第三个例程是第二个例程的反函数。将儒略日转换回普通日期。
/** *@brief Convert Julian Day into Calendar Date *@param julian Input for the Julian Day *@param month Output the corresponding month *@param day Output the corresponding day *@param year Output the corresponding year *Inverse of the function julday given above. Here julian is input as a Julian Day number, *and the routine outputs month, day, and year as the month, day, and year on which the *specified Julian Day stared at noon. */ void caldat(const int julian, int * const month, int * const day, int * const year){ const int IGREG = 2299161; int ja, jalpha, jb, jc, julian_day, je; if(julian >= IGREG){ //Cross-over to Gregorian Calendar produces this correction. jalpha = (int)((((double)(julian - 1867216)) - 0.25)/36524.25); ja = julian + 1 + jalpha - (int)(0.25*jalpha); } else if (julian < 0){ /* *Make day number positive by adding integer number of Julian centuries, *then subtract them off at the end. */ ja = julian + 36525 * (1 - julian/36525); } else { ja = julian; } jb = ja + 1524; jc = (int)(6680.0 + (((double)(jb-2439870))-122.1)/365.25); julian_day = (int)(365 * jc + (0.25*jc)); je = (int)((jb - julian_day)/30.6001); *day = jb - julian_day - (int)(30.6001*je); *month = je - 1; if(*month > 12) *month -= 12; *year = jc - 4715; if(*month > 2) --(*year); if(julian < 0) *year -= 100 * (1 - julian / 36525); } #endif // CALENDAR_H_INCLUDED
原书上的代码需要包含nr3.h,这样的话就必须要拿到他的nr3.h的头文件才行,也就是得买他的光盘了(有点小舍不得),所以呢,就将其中会用到的它自己实现的特性还原回了C的代码。这样的话,至少大家不会因为调试不出而直接失去对它的兴趣。
参考地址:
http://zh.wikipedia.org/wiki/%E5%84%92%E7%95%A5%E6%97%A5
http://www.fjptsz.com/xxjs/xjw/rj/117/07.htm