#ifndef __DT_ASTRO_COMMON_C__
#define __DT_ASTRO_COMMON_C__
#include "dt_astro.h"
STATIC_INLINE
int
__binary_search(mpfr_t *result, mpfr_t *lo, mpfr_t *hi,
int (*phi)(mpfr_t *, void *args, int n_args),
void *args,
int n_args,
int (*mu)(mpfr_t *, mpfr_t *)
) {
int loop = 1;
while (loop) {
mpfr_t x;
mpfr_init_set(x, *lo, GMP_RNDN);
mpfr_add(x, x, *hi, GMP_RNDN);
mpfr_div_ui(x, x, 2, GMP_RNDN);
if (mu(lo, hi) || mpfr_cmp(*hi, x) == 0 || mpfr_cmp(*lo, x) == 0) {
mpfr_set(*result, x, GMP_RNDN);
loop = 0;
} else if (phi(&x, args, n_args)) {
mpfr_set(*hi, x, GMP_RNDN);
} else {
mpfr_set(*lo, x, GMP_RNDN);
}
mpfr_clear(x);
}
return 1;
}
STATIC_INLINE
int
__search_next(mpfr_t *result, mpfr_t *base,
int (*check)(mpfr_t *x, void *args),
void *check_args,
int (*next_val)(mpfr_t *next, mpfr_t *x, void *args),
void *next_args
) {
mpfr_t x;
#if (0)
mpfr_fprintf(stderr,
"__search_next for %.10RNf\n", *base);
#endif
mpfr_init_set(x, *base, GMP_RNDN);
while ( ! check(&x, check_args) ) {
mpfr_t next;
mpfr_init(next);
next_val(&next, &x, next_args);
mpfr_set(x, next, GMP_RNDN);
mpfr_clear(next);
#if (0)
mpfr_fprintf(stderr,
"x = %.10RNf\n", x);
#endif
}
mpfr_set( *result, x, GMP_RNDN );
mpfr_clear(x);
return 1;
}
STATIC_INLINE
int
dt_astro_mod( mpfr_t *result, mpfr_t *target, mpfr_t *base ) {
mpfr_t p, r;
/* target - floor(target / base) * base */
mpfr_init_set( p, *target, GMP_RNDN );
mpfr_div( p, p, *base, GMP_RNDN );
mpfr_floor( p, p );
mpfr_mul( p, p, *base, GMP_RNDN );
mpfr_init_set( r, *target, GMP_RNDN );
mpfr_sub( *result, r, p, GMP_RNDN );
mpfr_clear(r);
mpfr_clear(p);
return 1;
}
STATIC_INLINE
int
dt_astro_sin( mpfr_t *result, mpfr_t *degrees ) {
mpfr_t pi2, r;
mpfr_init(pi2);
mpfr_const_pi(pi2, GMP_RNDN);
mpfr_mul_ui(pi2, pi2, 2, GMP_RNDN); /* pi * 2 */
mpfr_init_set(r, pi2, GMP_RNDN);
mpfr_div_ui(r, r, 360, GMP_RNDN);
mpfr_mul(r, r, *degrees, GMP_RNDN);
dt_astro_mod( &r, &r, &pi2 );
mpfr_sin( *result, r, GMP_RNDN );
mpfr_clear(r);
mpfr_clear(pi2);
return 1;
}
STATIC_INLINE
int
dt_astro_cos( mpfr_t *result, mpfr_t *degrees ) {
mpfr_t pi2, r;
mpfr_init(pi2);
mpfr_const_pi(pi2, GMP_RNDN);
mpfr_mul_ui(pi2, pi2, 2, GMP_RNDN); /* pi * 2 */
mpfr_init_set(r, pi2, GMP_RNDN);
mpfr_div_ui(r, r, 360, GMP_RNDN);
mpfr_mul(r, r, *degrees, GMP_RNDN);
dt_astro_mod( &r, &r, &pi2 );
mpfr_cos( *result, r, GMP_RNDN );
mpfr_clear(r);
mpfr_clear(pi2);
return 1;
}
STATIC_INLINE
int
dt_astro_polynomial( mpfr_t *result, mpfr_t *x, int howmany, mpfr_t **coefs) {
int i;
mpfr_t *m;
mpfr_set_ui( *result, 0, GMP_RNDN);
if (howmany <= 0) {
return 0;
}
m = coefs[0];
for (i = howmany - 1; i > 0; i--) {
mpfr_t p; /* v + next */
mpfr_init(p);
mpfr_add( p, *result, *(coefs[i]), GMP_RNDN );
mpfr_mul( *result, *x, p, GMP_RNDN );
mpfr_clear(p);
}
mpfr_add(*result, *result, *m, GMP_RNDN);
return 1;
}
STATIC_INLINE
int
polynomial(mpfr_t *result, mpfr_t *x, int howmany, ...) {
va_list argptr;
mpfr_t **coefs;
int i;
va_start(argptr, howmany);
mpfr_set_ui( *result, 0, GMP_RNDN );
Newxz(coefs, howmany, mpfr_t *);
for(i = 0; i < howmany; i++) {
coefs[i] = va_arg(argptr, mpfr_t *);
}
va_end(argptr);
dt_astro_polynomial( result, x, howmany, coefs);
Safefree(coefs);
return 1;
}
STATIC_INLINE
int
is_leap_year(int y) {
if (y % 4) return 0;
if (y % 100) return 1;
if (y % 400) return 0;
return 1;
}
STATIC_INLINE
long
gregorian_year_from_rd(long rd) {
double approx;
double start;
approx = floor( (rd - RD_GREGORIAN_EPOCH + 2) * 400 / 146097 );
start = RD_GREGORIAN_EPOCH + 365 * approx + floor(approx/4) - floor(approx/100) + floor(approx/400);
if (rd < start) {
return (int) approx;
} else {
return (int) (approx + 1);
}
}
STATIC_INLINE
int
fixed_from_ymd(int y, int m, int d) {
return
365 * (y -1) +
floor( (y - 1) / 4 ) -
floor( (y - 1) / 100 ) +
floor( (y - 1) / 400 ) +
floor( (367 * m - 362) / 12 ) +
( m <= 2 ? 0 :
m > 2 && is_leap_year(y) ? -1 :
-2
) + d
;
}
STATIC_INLINE
int
gregorian_components_from_rd(long rd, long *y, int *m, int *d) {
int prior_days;
*y = gregorian_year_from_rd( RD_GREGORIAN_EPOCH - 1 + rd + 306);
prior_days = rd - fixed_from_ymd( *y - 1, 3, 1 );
*m = (int) ( ((int) floor((5 * prior_days + 155) / 153) + 2) % 12 );
if (*m == 0) *m = 12;
*y = (long) (*y - floor( (*m + 9) / 12 ));
*d = (int) ( rd - fixed_from_ymd(*y, *m, 1) + 1);
return 1;
}
STATIC_INLINE
int
ymd_seconds_from_moment(mpfr_t *moment, long *y, int *m, int *d, int *s) {
long rd;
mpfr_t frac;
rd = mpfr_get_si( *moment, GMP_RNDN );
gregorian_components_from_rd( rd, y, m, d );
mpfr_init_set(frac, *moment, GMP_RNDN);
mpfr_sub_ui(frac, frac, rd, GMP_RNDN); /* now only fractional part */
mpfr_mul_ui(frac, frac, 86400, GMP_RNDN); /* now seconds */
*s = mpfr_get_si( frac, GMP_RNDN );
mpfr_clear(frac);
return 1;
}
static int
EC_C(mpfr_t *result, int y) {
mpfr_set_d(
*result,
fixed_from_ymd(y, 7, 1) - RD_MOMENT_1900_JAN_1,
GMP_RNDN
);
mpfr_div_ui( *result, *result, 3652510, GMP_RNDN );
return 1;
}
STATIC_INLINE
int
EC2(mpfr_t *correction, mpfr_t *ec_c) {
mpfr_t a, b, c, d, e, f, g, h;
mpfr_init_set_d(a, -0.00002, GMP_RNDN);
mpfr_init_set_d(b, 0.000297, GMP_RNDN);
mpfr_init_set_d(c, 0.025184, GMP_RNDN);
mpfr_init_set_d(d, -0.181133, GMP_RNDN);
mpfr_init_set_d(e, 0.553040, GMP_RNDN);
mpfr_init_set_d(f, -0.861938, GMP_RNDN);
mpfr_init_set_d(g, 0.677066, GMP_RNDN);
mpfr_init_set_d(h, -0.212591, GMP_RNDN);
polynomial(correction, ec_c, 8, &a, &b, &c, &d, &e, &f, &g, &h);
mpfr_clear(a);
mpfr_clear(b);
mpfr_clear(c);
mpfr_clear(d);
mpfr_clear(e);
mpfr_clear(f);
mpfr_clear(g);
mpfr_clear(h);
return 1;
}
STATIC_INLINE
int
EC3(mpfr_t *correction, mpfr_t *ec_c) {
mpfr_t a, b, c, d, e, f, g, h, i, j, k;
mpfr_init_set_d(a, -0.000009, GMP_RNDN);
mpfr_init_set_d(b, 0.003844, GMP_RNDN);
mpfr_init_set_d(c, 0.083563, GMP_RNDN);
mpfr_init_set_d(d, 0.865736, GMP_RNDN);
mpfr_init_set_d(e, 4.867575, GMP_RNDN);
mpfr_init_set_d(f, 15.845535, GMP_RNDN);
mpfr_init_set_d(g, 31.332267, GMP_RNDN);
mpfr_init_set_d(h, 38.291999, GMP_RNDN);
mpfr_init_set_d(i, 28.316289, GMP_RNDN);
mpfr_init_set_d(j, 11.636204, GMP_RNDN);
mpfr_init_set_d(k, 2.043794, GMP_RNDN);
polynomial(correction, ec_c, 11, &a, &b, &c, &d, &e, &f, &g, &h, &i, &j, &k);
mpfr_clear(a);
mpfr_clear(b);
mpfr_clear(c);
mpfr_clear(d);
mpfr_clear(e);
mpfr_clear(f);
mpfr_clear(g);
mpfr_clear(h);
mpfr_clear(i);
mpfr_clear(j);
mpfr_clear(k);
return 1;
}
STATIC_INLINE
int
EC4(mpfr_t *correction, int year) {
mpfr_t y, a, b, c, d;
mpfr_init_set_si(y, year, GMP_RNDN);
mpfr_init_set_d(a, 8.118780842, GMP_RNDN);
mpfr_init_set_d(b, -0.005092142, GMP_RNDN);
mpfr_init_set_d(c, 0.003336121, GMP_RNDN);
mpfr_init_set_d(d, -0.0000266484, GMP_RNDN);
polynomial(correction, &y, 4, &a, &b, &c, &d);
mpfr_div_ui(*correction, *correction, 86400, GMP_RNDN);
mpfr_clear(y);
mpfr_clear(a);
mpfr_clear(b);
mpfr_clear(c);
mpfr_clear(d);
return 1;
}
STATIC_INLINE
int
EC5(mpfr_t *correction, int year) {
mpfr_t y, a, b, c;
mpfr_init_set_si(y, year, GMP_RNDN);
mpfr_init_set_d(a, 196.58333, GMP_RNDN);
mpfr_init_set_d(b, -4.0675, GMP_RNDN);
mpfr_init_set_d(c, 0.0219167, GMP_RNDN);
polynomial(correction, &y, 3, &a, &b, &c);
mpfr_div_ui(*correction, *correction, 86400, GMP_RNDN);
mpfr_clear(y);
mpfr_clear(a);
mpfr_clear(b);
mpfr_clear(c);
return 1;
}
STATIC_INLINE
int
EC6(mpfr_t *correction, int year) {
mpfr_t x;
{ /* used to be called EC_X... now inlined */
mpfr_init(x);
mpfr_set_d(
x,
fixed_from_ymd(year, 1, 1) - RD_MOMENT_1810_JAN_1,
GMP_RNDN
);
}
mpfr_pow_ui( *correction, x, 2, GMP_RNDN );
mpfr_div_ui( *correction, *correction, 41048480, GMP_RNDN );
mpfr_sub_ui( *correction, *correction, 15, GMP_RNDN );
mpfr_div_ui( *correction, *correction, 86400, GMP_RNDN );
mpfr_clear(x);
return 1;
}
STATIC_INLINE
int
ephemeris_correction(mpfr_t *correction, int y) {
if (1988 <= y && y <= 2019) {
mpfr_set_si( *correction, y - 1933, GMP_RNDN );
mpfr_div_si( *correction, *correction, 86400, GMP_RNDN );
} else if ( 1900 <= y && y <= 1987 ) {
mpfr_t c;
mpfr_init(c);
EC_C(&c, y);
EC2(correction, &c);
mpfr_clear(c);
} else if ( 1800 <= y && y <= 1899 ) {
mpfr_t c;
mpfr_init(c);
EC_C(&c, y);
EC3(correction, &c);
mpfr_clear(c);
} else if ( 1700 <= y && y <= 1799 ) {
EC4(correction, y - 1700);
} else if ( 1620 <= y && y <= 1699 ) {
EC5(correction, y - 1600);
} else {
EC6(correction, y);
}
return 1;
}
STATIC_INLINE
int
dynamical_moment(mpfr_t *result, mpfr_t *moment) {
mpfr_t correction;
long rd;
mpfr_init(correction);
mpfr_set( *result, *moment, GMP_RNDN );
rd = mpfr_get_si(*moment, GMP_RNDN);
ephemeris_correction(&correction, gregorian_year_from_rd(rd));
#ifdef ANNOYING_DEBUG
#if (ANNOYING_DEBUG)
mpfr_fprintf(stderr,
"moment = %.10RNf, correction = %.10RNf\n",
*moment, correction);
#endif
#endif
mpfr_add( *result, *result, correction, GMP_RNDN );
mpfr_clear(correction);
return 1;
}
STATIC_INLINE
int
julian_centuries(mpfr_t *result, mpfr_t *moment) {
dynamical_moment(result, moment);
#ifdef ANNOYING_DEBUG
#if (ANNOYING_DEBUG)
mpfr_fprintf(stderr,
"moment = %.10RNf, dynamical = %.10RNf\n",
*moment, *result );
#endif
#endif
mpfr_sub_d( *result, *result, RD_MOMENT_J2000, GMP_RNDN );
mpfr_div_ui( *result, *result, 36525, GMP_RNDN );
return 1;
}
STATIC_INLINE
int
aberration(mpfr_t *result, mpfr_t *moment) {
/* 0.0000974 * cos( 177.63 + 35999.01848 * julian_centuries(moment) ) - 0.0005575 */
julian_centuries(result, moment);
mpfr_mul_d( *result, *result, 35999.01848, GMP_RNDN );
mpfr_add_d( *result, *result, 177.63, GMP_RNDN );
dt_astro_cos( result, result );
mpfr_mul_d( *result, *result, 0.000094, GMP_RNDN );
mpfr_sub_d( *result, *result, 0.0005575, GMP_RNDN );
return 1;
}
STATIC_INLINE
int
nutation( mpfr_t *result, mpfr_t *moment ) {
mpfr_t A, B, C;
mpfr_init(C);
julian_centuries(&C, moment);
{
mpfr_t a, b, c;
mpfr_init(A);
mpfr_init_set_d( a, 124.90, GMP_RNDN );
mpfr_init_set_d( b, -1934.134, GMP_RNDN );
mpfr_init_set_d( c, 0.002063, GMP_RNDN );
polynomial(&A, &C, 3, &a, &b, &c);
mpfr_clear(a);
mpfr_clear(b);
mpfr_clear(c);
}
{
mpfr_t a, b, c;
mpfr_init(B);
mpfr_init_set_d( a, 201.11, GMP_RNDN );
mpfr_init_set_d( b, 72001.5377, GMP_RNDN );
mpfr_init_set_d( c, 0.00057, GMP_RNDN );
polynomial(&B, &C, 3, &a, &b, &c);
mpfr_clear(a);
mpfr_clear(b);
mpfr_clear(c);
}
dt_astro_sin(&A, &A);
mpfr_mul_d(A, A, -0.004778, GMP_RNDN);
dt_astro_sin(&B, &B);
mpfr_mul_d(B, B, -0.0003667, GMP_RNDN);
mpfr_add(*result, A, B, GMP_RNDN);
mpfr_clear(A);
mpfr_clear(B);
mpfr_clear(C);
return 1;
}
#endif /** __DT_ASTRO_COMMON_C__ **/