diff options
Diffstat (limited to 'calendar.cpp')
-rw-r--r-- | calendar.cpp | 424 |
1 files changed, 424 insertions, 0 deletions
diff --git a/calendar.cpp b/calendar.cpp new file mode 100644 index 0000000..d869d5d --- /dev/null +++ b/calendar.cpp | |||
@@ -0,0 +1,424 @@ | |||
1 | // Encoding: UTF-8 | ||
2 | #include <iostream> | ||
3 | #include <string> | ||
4 | #include <vector> | ||
5 | #include <fstream> | ||
6 | #include <cmath> | ||
7 | #include <ctime> | ||
8 | using namespace std; | ||
9 | |||
10 | double pi=3.14159265358979323846; | ||
11 | double delta=5e-9; | ||
12 | |||
13 | typedef struct tm Date; | ||
14 | |||
15 | |||
16 | class Julian | ||
17 | { | ||
18 | private: | ||
19 | double d[23][5]={ | ||
20 | {-4000, 108371.700000, -13036.800000, 392.000000, 0.000000}, | ||
21 | { -500, 17201.000000, -627.820000, 16.170000, -0.341300}, | ||
22 | { -150, 12200.600000, -346.410000, 5.403000, -0.159300}, | ||
23 | { 150, 9113.800000, -328.130000, -1.647000, 0.037700}, | ||
24 | { 500, 5707.500000, -391.410000, 0.915000, 0.314500}, | ||
25 | { 900, 2203.400000, -283.450000, 13.034000, -0.177800}, | ||
26 | { 1300, 490.100000, -57.350000, 2.085000, -0.007200}, | ||
27 | { 1600, 120.000000, -9.810000, -1.532000, 0.140300}, | ||
28 | { 1700, 10.200000, -0.910000, 0.510000, -0.037000}, | ||
29 | { 1800, 13.400000, -0.720000, 0.202000, -0.019300}, | ||
30 | { 1830, 7.800000, -1.810000, 0.416000, -0.024700}, | ||
31 | { 1860, 8.300000, -0.130000, -0.406000, 0.029200}, | ||
32 | { 1880, -5.400000, 0.320000, -0.183000, 0.017300}, | ||
33 | { 1900, -2.300000, 2.060000, 0.169000, -0.013500}, | ||
34 | { 1920, 21.200000, 1.690000, -0.304000, 0.016700}, | ||
35 | { 1940, 24.200000, 1.220000, -0.064000, 0.003100}, | ||
36 | { 1960, 33.200000, 0.510000, 0.231000, -0.010900}, | ||
37 | { 1980, 51.000000, 1.290000, -0.026000, 0.003200}, | ||
38 | { 2000, 63.870000, 0.100000, 0.000000, 0.000000}, | ||
39 | { 2005, 64.700000, 0.210000, 0.000000, 0.000000}, | ||
40 | { 2012, 66.800000, 0.220000, 0.000000, 0.000000}, | ||
41 | { 2018, 69.000000, 0.360000, 0.000000, 0.000000}, | ||
42 | { 2028, 72.600000, 0.000000, 0.000000, 0.000000} | ||
43 | }; | ||
44 | |||
45 | double dt_ext(int y,double jsd) | ||
46 | { | ||
47 | double dy=(double)(y-1820)/100.0; | ||
48 | return -20+jsd*dy*dy; | ||
49 | } | ||
50 | |||
51 | //计算力学时与世界时之差,传入年份 | ||
52 | double delta_t(int y) | ||
53 | { | ||
54 | int y0=d[22][0];//表中最后一行的年份 | ||
55 | double t0=d[22][1];//表中最后一行的delta_t | ||
56 | double jsd; | ||
57 | |||
58 | if(y>y0) | ||
59 | { | ||
60 | jsd=31; | ||
61 | if(y-y0>100) | ||
62 | { | ||
63 | return dt_ext(y,jsd); | ||
64 | } | ||
65 | |||
66 | double v=dt_ext(y,jsd); | ||
67 | double dv=dt_ext(y0,jsd)-t0; | ||
68 | return v-dv*(y0+100-y)/100; | ||
69 | } | ||
70 | |||
71 | double res; | ||
72 | for(int i=0;i<22;i++) | ||
73 | { | ||
74 | if(y<d[i+1][0]) | ||
75 | { | ||
76 | break; | ||
77 | } | ||
78 | double t1=(y-d[i][0])/(d[i+1][0]-d[i][0])*10; | ||
79 | double t2=t1*t1; | ||
80 | double t3=t2*t1; | ||
81 | res=d[i][1]+d[i][2]*t1+d[i][3]*t2+d[i][4]*t3; | ||
82 | } | ||
83 | return res; | ||
84 | |||
85 | |||
86 | } | ||
87 | public: | ||
88 | // 计算儒略日 | ||
89 | double getJulianDay(time_t time) | ||
90 | { | ||
91 | double t=(double)time; | ||
92 | return (double)t/86400.0+2440587.5; | ||
93 | } | ||
94 | |||
95 | // 计算儒略千年数 | ||
96 | double getJulianKiloYear(time_t time) | ||
97 | { | ||
98 | double jd = getJulianDay(time); | ||
99 | return (double)(jd-2451545.0)/365250.0; | ||
100 | } | ||
101 | |||
102 | //儒略千年数转时间戳 | ||
103 | time_t kiloYearToTime(double t,int year) | ||
104 | { | ||
105 | double jd=t*365250.0+2451545.0; | ||
106 | time_t time=(time_t)((jd-2440587.5)*86400.0-delta_t(year)); | ||
107 | return time; | ||
108 | } | ||
109 | }; | ||
110 | |||
111 | class parameter{ | ||
112 | private: | ||
113 | |||
114 | // 计算地球日心黄经 | ||
115 | double get_longitude(vector<double> l,double t) | ||
116 | { | ||
117 | double L=l[0]; | ||
118 | for(int i=1;i<l.size();i++) | ||
119 | { | ||
120 | L+=l[i]*pow(t,i); | ||
121 | } | ||
122 | //返回弧度制 | ||
123 | return L+pi; | ||
124 | } | ||
125 | |||
126 | // 计算地球日心黄纬 | ||
127 | double get_latitude(vector<double> b,double t) | ||
128 | { | ||
129 | double B=b[0]; | ||
130 | for(int i=1;i<b.size();i++) | ||
131 | { | ||
132 | B+=b[i]*pow(t,i); | ||
133 | } | ||
134 | //返回弧度制 | ||
135 | //地心黄纬=-太阳黄纬 | ||
136 | return -B; | ||
137 | } | ||
138 | |||
139 | double get_R(vector<double> r,double t) | ||
140 | { | ||
141 | double R=r[0]; | ||
142 | for(int i=1;i<r.size();i++) | ||
143 | { | ||
144 | R+=r[i]*pow(t,i); | ||
145 | } | ||
146 | return R; | ||
147 | } | ||
148 | |||
149 | // 转换FK5误差,返回弧度制 | ||
150 | double delta_FK5(double L,double B,double T) | ||
151 | { | ||
152 | //L转角度制 | ||
153 | L*=180/pi; | ||
154 | //计算L',角度制 | ||
155 | double L_p=L-1.397*T-0.00031*T*T; | ||
156 | //计算L',弧度制 | ||
157 | L_p*=pi/180; | ||
158 | while(L_p<0) | ||
159 | L_p+=2*pi; | ||
160 | while(L_p>2*pi) | ||
161 | L_p-=2*pi; | ||
162 | //计算delta_L,单位为角秒 | ||
163 | double delta_L=-0.09033+0.03916*(cos(L_p)+sin(L_p))*tan(B); | ||
164 | //转换为弧度制 | ||
165 | delta_L*=pi/(180*3600); | ||
166 | return delta_L; | ||
167 | } | ||
168 | |||
169 | //获取章动有关角 | ||
170 | vector<double> get_angle(double T) | ||
171 | { | ||
172 | vector<double> ang; | ||
173 | //计算平距角 | ||
174 | ang.push_back(297.85036+445267.111480*T-0.0019142*T*T+T*T*T/189474); | ||
175 | //计算日地平近点角 | ||
176 | ang.push_back(357.52772+35999.050340*T-0.0001603*T*T-T*T*T/300000); | ||
177 | //计算月球平近点角 | ||
178 | ang.push_back(134.96298+477198.867398*T+0.0086972*T*T+T*T*T/56250); | ||
179 | //计算月球纬度参数 | ||
180 | ang.push_back(93.27191+483202.017538*T-0.0036825*T*T+T*T*T/327270); | ||
181 | //计算黄道与月球平轨道交点黄经 | ||
182 | ang.push_back(125.04452-1934.136261*T+0.0020708*T*T+T*T*T/450000); | ||
183 | return ang; | ||
184 | } | ||
185 | |||
186 | |||
187 | //章动修正 | ||
188 | double nution(double T) | ||
189 | { | ||
190 | vector<double> ang=get_angle(T); | ||
191 | fstream fr; | ||
192 | fr.open("data/nutation.txt",ios::in); | ||
193 | string str; | ||
194 | double sita; | ||
195 | double s,s1,s2; | ||
196 | double c,c1,c2; | ||
197 | double m,n,o,p,q; | ||
198 | |||
199 | s=c=0; | ||
200 | while(getline(fr,str)) | ||
201 | { | ||
202 | sscanf(str.c_str(),"%lf%lf%lf%lf%lf%lf%lf%lf%lf",&m,&n,&o,&p,&q,&s1,&s2,&c1,&c2); | ||
203 | sita=m*ang[0]+n*ang[1]+o*ang[2]+p*ang[3]+q*ang[4]; | ||
204 | |||
205 | //sita为角度制,转换为弧度制 | ||
206 | sita*=pi/180; | ||
207 | //计算黄经章动,单位为0.0001角秒 | ||
208 | s+=(s1+s2*T)*sin(sita); | ||
209 | //计算交角章动,单位为0.0001角秒 | ||
210 | //c+=(c1+c2*T)*cos(sita); | ||
211 | } | ||
212 | //关闭文件 | ||
213 | fr.close(); | ||
214 | // 计算得到的s和c单位0.0001秒,转换为弧度制 | ||
215 | s*=0.0001; | ||
216 | s*=pi/(180*3600); | ||
217 | return s; | ||
218 | } | ||
219 | |||
220 | //光行差修正,返回弧度制 | ||
221 | double aberration(double R) | ||
222 | { | ||
223 | //return -20.4898/R/3600.0*pi/180.0; | ||
224 | //公式,单位0.0001角秒 | ||
225 | double delta=-20.4898/R; | ||
226 | //转换为弧度制 | ||
227 | delta*=pi/(180*3600); | ||
228 | return delta; | ||
229 | } | ||
230 | |||
231 | // 获取地日运行参数,L为地球日心黄经,B为地球日心黄纬,R为地日距离 | ||
232 | vector<vector<double>> get_parameters(double t) | ||
233 | { | ||
234 | fstream fr; | ||
235 | fr.open("data/earth.txt",ios::in); | ||
236 | string s; | ||
237 | double l=0; | ||
238 | double a,b,c,num_tmp=0; | ||
239 | vector<vector<double>> parameters; | ||
240 | vector<double> tmp; | ||
241 | while(getline(fr,s)) | ||
242 | { | ||
243 | //当分割符为/时,表明一组参数结束,将参数存入parameters中,并清空tmp | ||
244 | if(s[0]=='/') | ||
245 | { | ||
246 | parameters.push_back(tmp); | ||
247 | tmp.resize(0); | ||
248 | num_tmp=0; | ||
249 | } | ||
250 | //当分割符为=时,表明一组参数中的一类结束,将参数存入tmp中,并清空num_tmp | ||
251 | else if(s[0]=='=') | ||
252 | { | ||
253 | tmp.push_back(num_tmp); | ||
254 | num_tmp=0; | ||
255 | } | ||
256 | else | ||
257 | { | ||
258 | sscanf(s.c_str(),"%lf%lf%lf",&a,&b,&c); | ||
259 | num_tmp+=a*cos(b+c*t); | ||
260 | } | ||
261 | } | ||
262 | //关闭文件 | ||
263 | fr.close(); | ||
264 | /* 最终传参情况: | ||
265 | * parameters[0]为L系列,用来计算地球日心黄经 | ||
266 | * parameters[1]为B系列,用来计算地球日心黄纬 | ||
267 | * parameters[2]为R系列,用来计算地日距离 | ||
268 | */ | ||
269 | return parameters; | ||
270 | } | ||
271 | |||
272 | public: | ||
273 | |||
274 | double longitude(double t) | ||
275 | { | ||
276 | //从文件中计算地日运行参数 | ||
277 | vector<vector<double>> p=get_parameters(t); | ||
278 | |||
279 | //取出各类参数 | ||
280 | vector<double> l=p[0],b=p[1],r=p[2]; | ||
281 | |||
282 | //计算地球日心黄经纬,返回弧度制/天文单位 | ||
283 | double L=get_longitude(l,t); | ||
284 | double B=get_latitude(b,t); | ||
285 | double R=get_R(r,t); | ||
286 | |||
287 | |||
288 | //以下修正需要的都是儒略世纪数而非千年数 | ||
289 | //转FK5误差,返回弧度制 | ||
290 | L+=delta_FK5(L,B,10*t); | ||
291 | //章动修正,返回弧度制 | ||
292 | L+=nution(10*t); | ||
293 | //光行差修正,返回弧度制 | ||
294 | L+=aberration(R); | ||
295 | |||
296 | |||
297 | //L转角度制 | ||
298 | L*=180/pi; | ||
299 | while(L<0) | ||
300 | L+=360; | ||
301 | while(L>=360) | ||
302 | L-=360; | ||
303 | if(360-L<=5) | ||
304 | { | ||
305 | L-=360; | ||
306 | } | ||
307 | return L; | ||
308 | } | ||
309 | }; | ||
310 | |||
311 | void Plus(Date &date) | ||
312 | { | ||
313 | if(date.tm_mday<10) | ||
314 | { | ||
315 | date.tm_mday=20; | ||
316 | } | ||
317 | else | ||
318 | { | ||
319 | date.tm_mday=6; | ||
320 | date.tm_mon++; | ||
321 | } | ||
322 | return; | ||
323 | } | ||
324 | |||
325 | double fuck(double a,double b) | ||
326 | { | ||
327 | while(b<0) | ||
328 | b+=360; | ||
329 | while(b>=360) | ||
330 | b-=360; | ||
331 | if(b==0) | ||
332 | { | ||
333 | return min(fabs(b),fabs(360-b)); | ||
334 | } | ||
335 | else | ||
336 | { | ||
337 | return fabs(a-b); | ||
338 | } | ||
339 | } | ||
340 | |||
341 | int main() | ||
342 | { | ||
343 | Date* date=new Date; | ||
344 | cout<<"Please input the year: "<<endl; | ||
345 | |||
346 | //时间确认 | ||
347 | cin>>date->tm_year; | ||
348 | date->tm_year-=1900;//年份减去1900 | ||
349 | //当年元旦零时 | ||
350 | date->tm_mon=0; | ||
351 | date->tm_mday=1; | ||
352 | date->tm_hour=0; | ||
353 | date->tm_min=0; | ||
354 | date->tm_sec=0; | ||
355 | |||
356 | //输出年份 | ||
357 | cout<<"Year: "<<date->tm_year+1900<<endl; | ||
358 | |||
359 | //计算当年二十四节气准确时刻 | ||
360 | parameter p; | ||
361 | Julian julian; | ||
362 | time_t time; | ||
363 | //double dL;//dL为L对t导数 | ||
364 | double t,t_end,t_middle; | ||
365 | double target; | ||
366 | char JieQi[24][10]={"小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至"}; | ||
367 | //date->tm_mday=6; | ||
368 | for(int i=0;date->tm_mon<12;Plus(*date),i++) | ||
369 | { | ||
370 | //转换为时间戳 | ||
371 | time=mktime(date); | ||
372 | //暂时放弃牛顿迭代法 | ||
373 | //t=julian.getJulianKiloYear(time); | ||
374 | //while(fuck(p.longitude(t),(double)i*15-75)>=1e-8) | ||
375 | //{ | ||
376 | // dL=(p.longitude(t+delta)-p.longitude(t-delta))/(2*delta); | ||
377 | // t=t-p.longitude(t)/dL; | ||
378 | //} | ||
379 | |||
380 | |||
381 | //计算儒略千年数 | ||
382 | t=julian.getJulianKiloYear(time); | ||
383 | t_end=julian.getJulianKiloYear(time+86400); | ||
384 | target=i*15-75; | ||
385 | if(target<0) | ||
386 | { | ||
387 | target+=360; | ||
388 | } | ||
389 | |||
390 | //二分法 | ||
391 | while(p.longitude(t)>target) | ||
392 | { | ||
393 | time-=86400; | ||
394 | t_end=t; | ||
395 | t=julian.getJulianKiloYear(time); | ||
396 | } | ||
397 | while(p.longitude(t_end)<=target) | ||
398 | { | ||
399 | time+=86400; | ||
400 | t=t_end; | ||
401 | t_end=julian.getJulianKiloYear(time); | ||
402 | } | ||
403 | while(t_end-t>=1e-10) | ||
404 | { | ||
405 | t_middle=(t+t_end)/2; | ||
406 | if(p.longitude(t_middle)>target) | ||
407 | { | ||
408 | t_end=t_middle; | ||
409 | } | ||
410 | else | ||
411 | { | ||
412 | t=t_middle; | ||
413 | } | ||
414 | } | ||
415 | //double t转为时间戳 | ||
416 | time=julian.kiloYearToTime(t,date->tm_year+1900); | ||
417 | |||
418 | //date换新 | ||
419 | date=localtime(&time); | ||
420 | printf("%d-%02d-%02d %02d:%02d:%02d %s\n",date->tm_year+1900,date->tm_mon+1,date->tm_mday,date->tm_hour,date->tm_min,date->tm_sec,JieQi[i]); | ||
421 | } | ||
422 | printf("\n\n"); | ||
423 | return 0; | ||
424 | } | ||