calendar.h -- 引起兴趣?儒略日?这是什么?

Adam posted @ Sat, 03 Mar 2012 00:09:57 +0800 in Numerical Receipes with tags c NumericalAlgebra , 2001 readers

《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

 


Login *


loading captcha image...
(type the code from the image)
or Ctrl+Enter