Numerical Ephemeris Calculation =============================== Mathematical method, constants, series and cross-language validation Version 0.5.3 - July 25, 2026 Abstract ======== This numerical core computes apparent topocentric ephemerides for asteroids, comets and interstellar objects from osculating orbital elements. Elliptic, parabolic and hyperbolic initial states are handled without an external orbit service. Numerical integration includes solar gravity, the first relativistic correction, planets, Earth and Moon, Earth J2, optionally 16 massive asteroids, and Marsden A1/A2/A3. Planetary and asteroid states are obtained from compact tables by cubic Hermite interpolation. The observed direction follows UTC-to-TDB conversion, light time, Earth rotation, nutation and precession. Six extreme objects and 20 frozen JPL Horizons rows form the common acceptance test for all 49 independent target-language programs. 1. Terms and symbols ==================== Every astronomical and numerical term required by the calculation is defined here. Important concepts are also explained briefly at their first use in the main text. Glossary of astronomical and numerical terms. Columns: Term | Meaning in this article Row: Term=Ephemeris | Meaning in this article=Predicted sequence of sky positions and related quantities for specified epochs and an observer. Row: Term=apparent | Meaning in this article=Direction after light time, Earth rotation, nutation and precession; atmospheric refraction is outside this core. Row: Term=topocentric | Meaning in this article=Referred to the actual observer on or near Earth's surface, rather than Earth's centre. Row: Term=geocentric / heliocentric | Meaning in this article=Referred respectively to the centre of Earth or the centre of the Sun. Row: Term=barycentre | Meaning in this article=Common centre of mass of several bodies; EMB denotes the Earth-Moon barycentre. Row: Term=osculating orbital elements | Meaning in this article=Six elements of the instantaneous Kepler orbit matching position and velocity at an epoch. Row: Term=epoch | Meaning in this article=Instant for which orbital elements or a state vector are valid. Row: Term=conic | Meaning in this article=Ellipse, parabola or hyperbola; eccentricity e distinguishes the three orbit forms. Row: Term=eccentricity e | Meaning in this article=Dimensionless shape parameter: e<1 ellipse, e=1 parabola, e>1 hyperbola. Row: Term=q, Tp, i, Omega, omega | Meaning in this article=Perihelion distance, perihelion epoch, inclination, ascending-node longitude and perihelion argument. Row: Term=M, E, H, nu | Meaning in this article=Mean, eccentric, hyperbolic and true anomaly; angle or auxiliary value locating the body on its orbit. Row: Term=J2000 | Meaning in this article=The fixed equatorial reference orientation at standard epoch JD 2451545.0 used by this core. Row: Term=AU | Meaning in this article=Astronomical unit, exactly 149597870.7 kilometres. Row: Term=JD | Meaning in this article=Julian date, the continuous astronomical day count. Row: Term=UTC / TAI / TDB | Meaning in this article=Coordinated Universal Time, International Atomic Time and barycentric dynamical time. Row: Term=leap second | Meaning in this article=Integer correction tying UTC to irregular Earth rotation while TAI remains uniform. Row: Term=gravitational parameter mu | Meaning in this article=Product G*M of gravitational constant and body mass; mu_sun is the solar value. Row: Term=mass ratio eta_b | Meaning in this article=Ratio M_b/M_sun of a perturbing body to the Sun, equal to mu_b/mu_sun. Row: Term=perturbing body | Meaning in this article=Body whose gravity adds acceleration beyond the pure two-body orbit. Row: Term=direct and indirect term | Meaning in this article=The body acts directly on the target; the simultaneous acceleration of the heliocentric origin is subtracted. Row: Term=N16 | Meaning in this article=Optional set of the 16 most massive asteroids integrated as additional perturbers. Row: Term=cubic Hermite interpolation | Meaning in this article=Third-degree interpolation reproducing position and velocity at both table nodes. Row: Term=little-endian float64 | Meaning in this article=Binary format storing the least significant byte first and IEEE-754 64-bit floating-point values. Row: Term=Runge-Kutta method | Meaning in this article=One-step method combining several derivative evaluations to advance the state. Row: Term=embedded method | Meaning in this article=Two Runge-Kutta solutions of different order share stages; their difference estimates local error. Row: Term=Dormand-Prince 5(4) | Meaning in this article=Embedded fifth- and fourth-order Runge-Kutta pair with seven stages. Row: Term=Butcher tableau | Meaning in this article=Tabular arrangement of Runge-Kutta coefficients c_i, a_ij and b_i defining stages and final weights. Row: Term=local error | Meaning in this article=Estimated error of one integration step, here the difference between fifth- and fourth-order solutions. Row: Term=adaptive step size | Meaning in this article=Automatic reduction or enlargement of the time step based on the normalized error estimate. Row: Term=RMS | Meaning in this article=Root mean square; here the square root of the mean of six squared, scaled component errors. Row: Term=clamp | Meaning in this article=Restriction of a number to a closed minimum-maximum interval. Row: Term=light time | Meaning in this article=Time required for light to travel from target to observer, shifting the evaluated emission epoch. Row: Term=precession / nutation | Meaning in this article=Slow secular and shorter-period changes in Earth's axis orientation. Row: Term=GMST | Meaning in this article=Greenwich mean sidereal time, the Earth rotation angle relative to the mean celestial frame. Row: Term=Earth J2 | Meaning in this article=Leading coefficient of Earth's gravity-field oblateness relative to an ideal point mass. Row: Term=Marsden A1/A2/A3 | Meaning in this article=Empirical comet acceleration in radial, transverse and normal directions. Row: Term=RA / declination | Meaning in this article=Right ascension and declination, the equatorial coordinate pair of the apparent direction. Row: Term=MPC rho factors | Meaning in this article=Dimensionless Minor Planet Center site factors for distance from Earth's axis and equatorial plane. Row: Term=arcsecond | Meaning in this article=1/3600 degree, denoted by the double-prime symbol. Row: Term=reference ephemeris / residual | Meaning in this article=JPL Horizons comparison position and the remaining spherical angular separation. Row: Term=covariance propagation | Meaning in this article=Propagation of statistical orbit uncertainties and correlations; outside this nominal core. Row: Term=acceptance test | Meaning in this article=Fixed comparison whose limit a port must meet before release. Solar and terrestrial gravitational parameters are kept unambiguous. Columns: Symbol | Meaning | Value or unit Row: Symbol=mu_sun = G*M_sun | Meaning=Heliocentric gravitational parameter of the Sun | Value or unit=0.0002959122082855911 AU cubed/day squared Row: Symbol=mu_E = G*M_E | Meaning=Geocentric gravitational parameter of Earth | Value or unit=8.887692445125148326e-10 AU cubed/day squared Row: Symbol=mu_Moon = G*M_Moon | Meaning=Gravitational parameter of the Moon | Value or unit=1.09318946230584718e-11 AU cubed/day squared Row: Symbol=eta_b = mu_b/mu_sun | Meaning=Mass ratio of perturbing body b to the Sun | Value or unit=dimensionless Row: Symbol=r, v, a | Meaning=Position, velocity and acceleration vector | Value or unit=AU; AU/day; AU/day squared Row: Symbol=t0, Tp, Delta | Meaning=Element epoch, perihelion epoch and t0-Tp | Value or unit=JD or days Row: Symbol=q, a, p, e | Meaning=Perihelion distance, semimajor axis, semilatus rectum and eccentricity | Value or unit=AU or dimensionless Row: Symbol=M, E, H, nu | Meaning=Mean, eccentric, hyperbolic and true anomaly | Value or unit=radians Row: Symbol=Omega, omega, i | Meaning=Ascending node, argument of perihelion and inclination | Value or unit=input degrees; internal radians Row: Symbol=c | Meaning=Speed of light | Value or unit=173.144632674240 AU/day Row: Symbol=rho | Meaning=Topocentric target vector, or Earth distance in the J2 section | Value or unit=AU Row: Symbol=J2, R_E | Meaning=Earth oblateness coefficient and equatorial radius | Value or unit=dimensionless and AU Row: Symbol=A1, A2, A3 | Meaning=Marsden non-gravitational parameters | Value or unit=AU/day squared Row: Symbol=T | Meaning=Julian centuries since J2000 | Value or unit=dimensionless 2. Conventions, gravitational parameters and base quantities ============================================================ The dynamical state y=[x,y,z,vx,vy,vz] is heliocentric, right-handed and referred to the equatorial J2000 frame. Position is in AU, velocity in AU/day and acceleration in AU/day squared. Internal angles are radians; public orbital elements, geographic inputs and result angles are degrees. The symbol mu denotes a gravitational parameter mu=G*M, the product of gravitational constant G and body mass M. To avoid ambiguity this article always writes mu_sun=G*M_sun for the Sun and mu_E=G*M_E for Earth. For a perturbing body b, eta_b=mu_b/mu_sun=M_b/M_sun. Columns: Quantity | Exact value | Unit Row: Quantity=pi | Exact value=3.141592653589793238462643383279502884 | Unit=dimensionless Row: Quantity=AU | Exact value=149597870.7 | Unit=km Row: Quantity=mu_sun = G*M_sun | Exact value=0.0002959122082855911 | Unit=AU cubed/day squared Row: Quantity=mu_E = G*M_E | Exact value=8.887692445125148326e-10 | Unit=AU cubed/day squared Row: Quantity=mu_Moon = G*M_Moon | Exact value=1.09318946230584718e-11 | Unit=AU cubed/day squared Row: Quantity=speed of light | Exact value=173.144632674240 | Unit=AU/day Row: Quantity=light time | Exact value=0.0057755183 | Unit=day/AU Row: Quantity=Earth/Sun mass | Exact value=3.0034896149156e-6 | Unit=dimensionless Row: Quantity=Moon/Sun mass | Exact value=3.6943033497651e-8 | Unit=dimensionless Row: Quantity=Earth radius | Exact value=6378.1363 / 149597870.7 | Unit=AU Row: Quantity=Earth J2 | Exact value=1.08262668e-3 | Unit=dimensionless Row: Quantity=J2000 obliquity | Exact value=84381.448 | Unit=arcseconds 3. Initial state from osculating elements ========================================= Inputs are epoch t0, eccentricity e, perihelion distance q, perihelion epoch Tp, ascending node Omega, argument of perihelion omega and inclination i. Osculating means that these elements reproduce the position and velocity of the perturbed orbit at their epoch. With mu_sun=G*M_sun and Delta=t0-Tp, the true anomaly nu is determined first. 3.1 Ellipse ----------- Validity: e < 1 - 1e-8 a = q / (1 - e) n = sqrt(mu_sun / a^3) M = normalize(n Delta, -pi, +pi) E0 = M when e < 0.8 E0 = sign(M) pi otherwise E(k+1) = Ek - (Ek - e sin Ek - M) / (1 - e cos Ek) Stop: |correction| < 2e-14 or after 80 iterations nu = 2 atan2(sqrt(1+e) sin(E/2), sqrt(1-e) cos(E/2)) 3.2 Hyperbola ------------- Validity: e > 1 + 1e-8 a = q / (e - 1) (positive magnitude convention) M = sqrt(mu_sun / a^3) Delta H0 = asinh(M / e) H(k+1) = Hk - (e sinh Hk - Hk - M) / (e cosh Hk - 1) Stop: |correction| < 2e-14 or after 80 iterations nu = 2 atan2(sqrt(e+1) sinh(H/2), sqrt(e-1) cosh(H/2)) 3.3 Parabola and the near-parabolic boundary -------------------------------------------- Validity: |e - 1| <= 1e-8 s = sqrt(2 q^3 / mu_sun) B = Delta / s D = 2 sinh(asinh(1.5 B) / 3) nu = 2 atan D Barker's form avoids the ill-conditioned division by 1-e or e-1 in the immediate parabolic boundary. The following equations then apply to all three conics: p = q (1 + e) r = p / (1 + e cos nu) v0 = sqrt(mu_sun / p) r_orb = [r cos nu, r sin nu, 0] v_orb = [-v0 sin nu, v0 (e + cos nu), 0] Rotation from the orbital plane uses Rz(Omega) Rx(i) Rz(omega). For a two-dimensional input [x,y], the expanded form is: X = (cosOmega cosomega - sinOmega sinomega cosi) x + (-cosOmega sinomega - sinOmega cosomega cosi) y Y = (sinOmega cosomega + cosOmega sinomega cosi) x + (-sinOmega sinomega + cosOmega cosomega cosi) y Z = (sinomega sini) x + (cosomega sini) y A fixed x-axis rotation by 84381.448 arcseconds then transforms J2000 ecliptic position and velocity to the equatorial frame. 4. Perturber tables and Hermite interpolation ============================================= Each table node stores position r0 and velocity v0. For two nodes separated by h and u=(t-t0)/h, the core uses the following complete cubic Hermite basis and exact numerical coefficients: h00(u) = 2 u^3 - 3 u^2 + 1 h10(u) = u^3 - 2 u^2 + u h01(u) = -2 u^3 + 3 u^2 h11(u) = u^3 - u^2 r(u) = h00 r0 + h10 h v0 + h01 r1 + h11 h v1 dh00/dt = ( 6 u^2 - 6 u) / h dh10/dt = 3 u^2 - 4 u + 1 dh01/dt = (-6 u^2 + 6 u) / h dh11/dt = 3 u^2 - 2 u v(u) = (dh00/dt) r0 + dh10 v0 + (dh01/dt) r1 + dh11 v1 Columns: Perturbing body | Mass/Sun mass Row: Perturbing body=Mercury | Mass/Sun mass=1.660114153054348e-7 Row: Perturbing body=Venus | Mass/Sun mass=2.447838287784771e-6 Row: Perturbing body=Mars | Mass/Sun mass=3.227156037554996e-7 Row: Perturbing body=Jupiter | Mass/Sun mass=9.547919101886966e-4 Row: Perturbing body=Saturn | Mass/Sun mass=2.858856727222416e-4 Row: Perturbing body=Uranus | Mass/Sun mass=4.366249662744965e-5 Row: Perturbing body=Neptune | Mass/Sun mass=5.151383772628673e-5 Row: Perturbing body=Pluto | Mass/Sun mass=7.350487833457740e-9 Columns: N16 body | Mass/Sun mass Row: N16 body=Ceres | Mass/Sun mass=4.719154706681575e-10 Row: N16 body=Pallas | Mass/Sun mass=1.0297360324108826e-10 Row: N16 body=Juno | Mass/Sun mass=1.4471670474939703e-11 Row: N16 body=Vesta | Mass/Sun mass=1.3026875547328177e-10 Row: N16 body=Iris | Mass/Sun mass=8.589038999387399e-12 Row: N16 body=Hygiea | Mass/Sun mass=4.238598614896659e-11 Row: N16 body=Eunomia | Mass/Sun mass=1.5243642468487352e-11 Row: N16 body=Psyche | Mass/Sun mass=1.1978215785019767e-11 Row: N16 body=Euphrosyne | Mass/Sun mass=8.133159614634648e-12 Row: N16 body=Europa | Mass/Sun mass=2.0216913527078825e-11 Row: N16 body=Cybele | Mass/Sun mass=7.06871003275745e-12 Row: N16 body=Sylvia | Mass/Sun mass=1.6337820878172953e-11 Row: N16 body=Thisbe | Mass/Sun mass=8.965306556356798e-12 Row: N16 body=Camilla | Mass/Sun mass=1.0878696848144257e-11 Row: N16 body=Davida | Mass/Sun mass=2.9345275747768696e-11 Row: N16 body=Interamnia | Mass/Sun mass=2.1327387533901138e-11 5. Equation of motion ===================== d/dt [r, v] = [v, a(r,v,t)] The solar base acceleration is a_s=-mu_sun r/|r|^3. A perturbing body at heliocentric position r_b and with mass ratio eta_b contributes the direct and indirect terms together: a_b = mu_sun eta_b [(r_b - r)/|r_b - r|^3 - r_b/|r_b|^3] Earth and Moon are treated separately inside 0.2 AU and as the Earth-Moon barycentre outside it. Mercury, Venus, Mars, Jupiter, Saturn, Uranus, Neptune and Pluto are always active. N16 is added only when the switch is set and all data are present. 5.1 Relativistic solar correction --------------------------------- a_rel = mu_sun / (c^2 |r|^3) * [(4 mu_sun/|r| - |v|^2) r + 4 (r dot v) v] 5.2 Earth J2 ------------ Inside 0.02 AU from Earth, the usual J2 acceleration is added as a direct-minus-indirect term in this port's approximate Earth-axis frame: mu_E = G*M_E = 8.887692445125148326e-10 AU^3/day^2 k = 1.5 J2 mu_E R_E^2 / rho^5 a_J2,x = k x (5 z^2/rho^2 - 1) a_J2,y = k y (5 z^2/rho^2 - 1) a_J2,z = k z (5 z^2/rho^2 - 3) 5.3 Non-gravitational acceleration ---------------------------------- g(r) = alpha (r/r0)^(-m) [1 + (r/r0)^n]^(-k) Defaults: r0=2.808, alpha=0.1112620426, m=2.15, n=5.093, k=4.6142 a_ng = g(r) [A1 e_r + A2 e_t + A3 e_n] e_r is radial, e_n is normal to the orbital plane along r cross v, and e_t=e_n cross e_r is transverse. When A1=A2=A3=0 the exact zero vector is returned. 6. Dormand-Prince 5(4) ====================== An embedded Runge-Kutta pair produces fifth- and fourth-order solutions from shared stages; their difference estimates the local error. A Butcher tableau is the tabular collection of stage abscissae c_i, intermediate weights a_ij and final weights b_i. It therefore defines the complete integration step. All coefficients used by the core are: c2=1/5; a21=1/5 c3=3/10; a31=3/40; a32=9/40 c4=4/5; a41=44/45; a42=-56/15; a43=32/9 c5=8/9; a51=19372/6561; a52=-25360/2187; a53=64448/6561; a54=-212/729 c6=1; a61=9017/3168; a62=-355/33; a63=46732/5247; a64=49/176; a65=-5103/18656 c7=1; a71=35/384; a72=0; a73=500/1113; a74=125/192; a75=-2187/6784; a76=11/84 Order 5: b = [35/384, 0, 500/1113, 125/192, -2187/6784, 11/84, 0] Order 4: b*= [5179/57600, 0, 7571/16695, 393/640, -92097/339200, 187/2100, 1/40] For every state component, scale=2e-15+2e-13*max(|y_old|,|y_new|). The normalized RMS error is sqrt(sum((error/scale)^2)/6). A step is accepted for error <=1 or |h|<=1e-8 day. The next factor is clamp(0.9*error^(-0.2),0.1,5), or 5 for zero error. Step size stays between 1e-8 and 0.25 day, and one propagation may take at most 1,000,000 steps. 7. Time scales and observer =========================== The public time scale is UTC. Dynamics use the approximation TDB=UTC+(TAI-UTC+32.184 s)/86400. The implemented leap-second steps are: JD >= 2457754.5 : TAI-UTC = 37 s JD >= 2457204.5 : TAI-UTC = 36 s JD >= 2456109.5 : TAI-UTC = 35 s JD >= 2454832.5 : TAI-UTC = 34 s JD >= 2453736.5 : TAI-UTC = 33 s otherwise : TAI-UTC = 32 s With T=(JD_UTC-2451545)/36525, GMST and the complete short nutation and precession series used by the port are: GMST = 280.46061837 + 360.98564736629 (JD-2451545) + 0.000387933 T^2 - T^3/38710000 L_sun = 280.4665 + 36000.7698 T [degrees] L_moon = 218.3165 + 481267.8813 T [degrees] Omega_moon = 125.04452 - 1934.136261 T [degrees] Delta_psi = -17.20 sin Omega_moon -1.32 sin(2 L_sun) -0.23 sin(2 L_moon) +0.21 sin(2 Omega_moon) [arcsec] Delta_eps = 9.20 cos Omega_moon +0.57 cos(2 L_sun) +0.10 cos(2 L_moon) -0.09 cos(2 Omega_moon) [arcsec] eps0 = 23 + 26/60 + 21.448/3600 degrees -(46.8150 T + 0.00059 T^2 - 0.001813 T^3) arcsec zeta = 2306.2181 T + 0.30188 T^2 + 0.017998 T^3 arcsec z = 2306.2181 T + 1.09468 T^2 + 0.018203 T^3 arcsec theta = 2004.3109 T - 0.42665 T^2 - 0.041833 T^3 arcsec The geocentric site vector is formed from MPC rho factors or geodetic longitude, latitude and height, rotated by apparent sidereal time, then returned to J2000 through nutation and precession. 8. Light time and apparent direction ==================================== Earth and observer states remain at reception time. Emission time is iterated at most five times: t_emit,0 = t_TDB rho_k = r_object(t_emit,k) - r_earth(t_TDB) - r_observer(t_UTC) t_emit,k+1 = t_TDB - |rho_k| * 0.0057755183 Stop: |t_emit,k+1 - t_emit,k| < 1e-12 day RA = normalize(atan2(rho_y,rho_x), 0, 2 pi) Dec = atan2(rho_z, sqrt(rho_x^2+rho_y^2)) 9. Binary tables ================ Planet chunks cover 2000 through 2040 in nine overlapping intervals at 0.5-day spacing. N16 also uses nine chunks at exactly 1.9999817474948436 days. Overlap permits safe Hermite interpolation at boundaries. Every value is little-endian float64. Columns: Dataset | Interval | Step | Content Row: Dataset=Planets | Interval=2000-2040 | Step=0.5 day | Content=11 bodies: EMB, Earth, Moon, Mercury through Pluto Row: Dataset=N16 | Interval=2000-2040 | Step=1.9999817474948436 days | Content=16 massive asteroids 10. Extreme examples ==================== The following tables list UTC, frozen JPL Horizons reference values, the C-port result and the approximately spherical angular separation. Station A68 and identical nominal elements were used. Angles are degrees. Orbit form and perihelion distance of the six validation cases. Columns: Object | Epoch JD | e | q AU Row: Object=433 Eros | Epoch JD=2453311.5 | e=0.2228078944584026 | q AU=1.133355399799004 Row: Object=C/2023 A3 | Epoch JD=2460448.5 | e=1.000095309222603 | q AU=0.3914300307809727 Row: Object=2P Encke | Epoch JD=2459847.5 | e=0.8477496967533629 | q AU=0.3379482792219925 Row: Object=2I Borisov | Epoch JD=2458853.5 | e=3.356475782676596 | q AU=2.006520878500843 Row: Object=99942 Apophis | Epoch JD=2459215.5 | e=0.19152168935010219 | q AU=0.74582704784665232 Row: Object=367943 Duende | Epoch JD=2456158.5 | e=0.10812843436824709 | q AU=0.893491631652941 Perihelion epoch and orbital-plane orientation. Columns: Object | Tp TDB | Omega deg | omega deg | i deg Row: Object=433 Eros | Tp TDB=2453371.5859943051 | Omega deg=304.40102733795362 | omega deg=178.665326776373 | i deg=10.8291838260782 Row: Object=C/2023 A3 | Tp TDB=2460581.24084083 | Omega deg=21.55947863619833 | omega deg=308.4917712569641 | i deg=139.1121095087364 Row: Object=2P Encke | Tp TDB=2460239.6495185494 | Omega deg=334.1935846036774 | omega deg=187.1342463695676 | i deg=11.41227811179314 Row: Object=2I Borisov | Tp TDB=2458826.052845906 | Omega deg=308.1477292269942 | omega deg=209.1236864378081 | i deg=44.05264247909138 Row: Object=99942 Apophis | Tp TDB=2459101.0394224627 | Omega deg=204.0389272089208 | omega deg=126.65205183685531 | i deg=3.3367513200667558 Row: Object=367943 Duende | Tp TDB=2456261.554400227 | Omega deg=147.2625010881184 | omega deg=271.08746874977783 | i deg=10.33728752192523 Non-gravitational parameters; zero omits that component. Columns: Object | A1 / A2 / A3 Row: Object=433 Eros | A1 / A2 / A3=0 / 0 / 0 Row: Object=C/2023 A3 | A1 / A2 / A3=1.4218744044776211e-8 / 1.3486232284695711e-9 / 0 Row: Object=2P Encke | A1 / A2 / A3=2.34758107815004e-10 / -6.540690743894436e-13 / 0 Row: Object=2I Borisov | A1 / A2 / A3=4.8595882640274848e-8 / 1.8798986909513609e-8 / 2.8355032201284751e-9 Row: Object=99942 Apophis | A1 / A2 / A3=5e-13 / -2.9017666371531647e-14 / 0 Row: Object=367943 Duende | A1 / A2 / A3=0 / 0 / 0 Frozen JPL Horizons reference positions. Columns: Object | UTC | JPL RA deg | JPL Dec deg Row: Object=433 Eros | UTC=2026-07-21 22:00:00 | JPL RA deg=188.352878680 | JPL Dec deg=-15.485731924 Row: Object=433 Eros | UTC=2026-07-22 22:00:00 | JPL RA deg=189.033073621 | JPL Dec deg=-15.673602566 Row: Object=433 Eros | UTC=2026-07-23 22:00:00 | JPL RA deg=189.712493431 | JPL Dec deg=-15.860306533 Row: Object=C/2023 A3 | UTC=2026-07-21 22:00:00 | JPL RA deg=270.131469713 | JPL Dec deg=20.765253967 Row: Object=C/2023 A3 | UTC=2026-07-22 22:00:00 | JPL RA deg=269.997011490 | JPL Dec deg=20.710979861 Row: Object=C/2023 A3 | UTC=2026-07-23 22:00:00 | JPL RA deg=269.864375552 | JPL Dec deg=20.655473422 Row: Object=2P Encke | UTC=2026-07-21 22:00:00 | JPL RA deg=22.086326480 | JPL Dec deg=16.151079557 Row: Object=2P Encke | UTC=2026-07-22 22:00:00 | JPL RA deg=22.204227929 | JPL Dec deg=16.258348832 Row: Object=2P Encke | UTC=2026-07-23 22:00:00 | JPL RA deg=22.318311808 | JPL Dec deg=16.365096989 Row: Object=2I Borisov | UTC=2019-12-08 00:00:00 | JPL RA deg=171.852537543 | JPL Dec deg=-17.895950115 Row: Object=2I Borisov | UTC=2019-12-09 00:00:00 | JPL RA deg=172.269466247 | JPL Dec deg=-18.665188729 Row: Object=2I Borisov | UTC=2019-12-10 00:00:00 | JPL RA deg=172.685173642 | JPL Dec deg=-19.435471809 Row: Object=99942 Apophis | UTC=2029-04-13 20:30:00 | JPL RA deg=162.187610650 | JPL Dec deg=-1.853259832 Row: Object=99942 Apophis | UTC=2029-04-13 20:40:00 | JPL RA deg=158.279644424 | JPL Dec deg=0.774049246 Row: Object=99942 Apophis | UTC=2029-04-13 20:50:00 | JPL RA deg=153.882081064 | JPL Dec deg=3.710242552 Row: Object=99942 Apophis | UTC=2029-04-13 21:00:00 | JPL RA deg=148.942949743 | JPL Dec deg=6.944475706 Row: Object=367943 Duende | UTC=2013-02-15 19:15:00 | JPL RA deg=180.339825182 | JPL Dec deg=-21.468034850 Row: Object=367943 Duende | UTC=2013-02-15 19:20:00 | JPL RA deg=180.569814701 | JPL Dec deg=-17.847154119 Row: Object=367943 Duende | UTC=2013-02-15 19:25:00 | JPL RA deg=180.799653390 | JPL Dec deg=-14.126076156 Row: Object=367943 Duende | UTC=2013-02-15 19:30:00 | JPL RA deg=181.029779486 | JPL Dec deg=-10.326525675 Calculated positions and spherical separation from the reference. Columns: Object | UTC | Core RA deg | Core Dec deg | Delta arcsec Row: Object=433 Eros | UTC=2026-07-21 22:00:00 | Core RA deg=188.352878496 | Core Dec deg=-15.485732361 | Delta arcsec=0.001696 Row: Object=433 Eros | UTC=2026-07-22 22:00:00 | Core RA deg=189.033073460 | Core Dec deg=-15.673603008 | Delta arcsec=0.001687 Row: Object=433 Eros | UTC=2026-07-23 22:00:00 | Core RA deg=189.712493295 | Core Dec deg=-15.860306981 | Delta arcsec=0.001680 Row: Object=C/2023 A3 | UTC=2026-07-21 22:00:00 | Core RA deg=270.131471956 | Core Dec deg=20.765254400 | Delta arcsec=0.007710 Row: Object=C/2023 A3 | UTC=2026-07-22 22:00:00 | Core RA deg=269.997013729 | Core Dec deg=20.710980297 | Delta arcsec=0.007701 Row: Object=C/2023 A3 | UTC=2026-07-23 22:00:00 | Core RA deg=269.864377787 | Core Dec deg=20.655473860 | Delta arcsec=0.007693 Row: Object=2P Encke | UTC=2026-07-21 22:00:00 | Core RA deg=22.086326254 | Core Dec deg=16.151079161 | Delta arcsec=0.001626 Row: Object=2P Encke | UTC=2026-07-22 22:00:00 | Core RA deg=22.204227701 | Core Dec deg=16.258348433 | Delta arcsec=0.001638 Row: Object=2P Encke | UTC=2026-07-23 22:00:00 | Core RA deg=22.318311578 | Core Dec deg=16.365096587 | Delta arcsec=0.001650 Row: Object=2I Borisov | UTC=2019-12-08 00:00:00 | Core RA deg=171.852535053 | Core Dec deg=-17.895966055 | Delta arcsec=0.058015 Row: Object=2I Borisov | UTC=2019-12-09 00:00:00 | Core RA deg=172.269463755 | Core Dec deg=-18.665203001 | Delta arcsec=0.052076 Row: Object=2I Borisov | UTC=2019-12-10 00:00:00 | Core RA deg=172.685171171 | Core Dec deg=-19.435484512 | Delta arcsec=0.046495 Row: Object=99942 Apophis | UTC=2029-04-13 20:30:00 | Core RA deg=162.187667572 | Core Dec deg=-1.853286529 | Delta arcsec=0.226242 Row: Object=99942 Apophis | UTC=2029-04-13 20:40:00 | Core RA deg=158.279702838 | Core Dec deg=0.774021995 | Delta arcsec=0.232031 Row: Object=99942 Apophis | UTC=2029-04-13 20:50:00 | Core RA deg=153.882138225 | Core Dec deg=3.710216547 | Delta arcsec=0.225683 Row: Object=99942 Apophis | UTC=2029-04-13 21:00:00 | Core RA deg=148.943005706 | Core Dec deg=6.944451473 | Delta arcsec=0.218189 Row: Object=367943 Duende | UTC=2013-02-15 19:15:00 | Core RA deg=180.339837945 | Core Dec deg=-21.468014339 | Delta arcsec=0.085326 Row: Object=367943 Duende | UTC=2013-02-15 19:20:00 | Core RA deg=180.569829577 | Core Dec deg=-17.847141796 | Delta arcsec=0.067577 Row: Object=367943 Duende | UTC=2013-02-15 19:25:00 | Core RA deg=180.799668504 | Core Dec deg=-14.126072752 | Delta arcsec=0.054168 Row: Object=367943 Duende | UTC=2013-02-15 19:30:00 | Core RA deg=181.029797039 | Core Dec deg=-10.326531491 | Delta arcsec=0.065598 433 Eros checks an ordinary ellipse. C/2023 A3 is near-parabolic and contains A1/A2. 2P/Encke is a periodic comet with non-gravitational acceleration. 2I/Borisov enforces e=3.356475782676596 with A1/A2/A3. Apophis and Duende test rapid apparent motion during close Earth passages. 11. Reproducibility and limitations =================================== * The one-arcsecond limit applies to the same frozen nominal elements, not to a later orbit solution. * The short nutation, precession and TDB approximation targets the documented interval and accuracy. * Leap seconds after the last built-in step must be added before later epochs are used. * The tables cover 2000 through 2040; other intervals require a new dataset. * Uncertainty ellipses and covariance propagation are outside this nominal core. * Find_Orb is neither runtime component nor fallback; it is used only for private local comparison. Appendix A. Comparison of programming languages =============================================== Every successful edition passed the same 20 reference rows. Accuracy is sorted alphabetically by language. The separate timing table is sorted by ascending median time, fastest first. Each language calculated six cases seven times in an alternating cross-language order. These numbers show only relative performance on this test computer. A.1 Accuracy, alphabetical -------------------------- Maximum spherical angular separation over all 20 reference rows. Columns: Language | Max. Delta arcsec | Result | Source B | Package B | Toolchain Row: Language=Ada | Max. Delta arcsec=0.223931 | Result=PASS | Source B=65,773 | Package B=520,661 | Toolchain=GNAT/GCC 15.2.0 (MSYS2) Row: Language=B4X | Max. Delta arcsec=0.232382 | Result=PASS | Source B=63,915 | Package B=550,906 | Toolchain=B4J 10.50 Row: Language=Ballerina | Max. Delta arcsec=0.238317 | Result=PASS | Source B=54,944 | Package B=546,455 | Toolchain=Ballerina Swan Lake 2201.13.4 Row: Language=BlitzMax | Max. Delta arcsec=1.203843 | Result=PASS | Source B=91,196 | Package B=549,418 | Toolchain=BlitzMax NG 0.154.3.58 Row: Language=C | Max. Delta arcsec=0.232031 | Result=PASS | Source B=55,659 | Package B=565,802 | Toolchain=GCC 16.1.0 Row: Language=C# | Max. Delta arcsec=0.232031 | Result=PASS | Source B=50,345 | Package B=545,734 | Toolchain=.NET SDK 8.0.423 Row: Language=C++ | Max. Delta arcsec=0.238317 | Result=PASS | Source B=56,461 | Package B=546,717 | Toolchain=Microsoft Visual C++ Community Row: Language=Clojure | Max. Delta arcsec=0.235614 | Result=PASS | Source B=45,101 | Package B=486,240 | Toolchain=Clojure 1.12.5 / OpenJDK Row: Language=Common Lisp | Max. Delta arcsec=0.223203 | Result=PASS | Source B=45,225 | Package B=496,773 | Toolchain=SBCL 2.6.6 Row: Language=D | Max. Delta arcsec=0.250215 | Result=PASS | Source B=38,210 | Package B=514,240 | Toolchain=DMD 2.112.0 Row: Language=Dart | Max. Delta arcsec=0.228185 | Result=PASS | Source B=42,668 | Package B=538,284 | Toolchain=Dart 3.12.2 Row: Language=Delphi/Object Pascal | Max. Delta arcsec=0.232316 | Result=PASS | Source B=56,636 | Package B=524,660 | Toolchain=Free Pascal 3.2.2 Row: Language=Elixir | Max. Delta arcsec=0.243787 | Result=PASS | Source B=53,273 | Package B=575,919 | Toolchain=Elixir 1.20.2 / Erlang OTP 29 Row: Language=Erlang | Max. Delta arcsec=0.243787 | Result=PASS | Source B=52,475 | Package B=583,700 | Toolchain=Erlang/OTP 29.0.3 Row: Language=F# | Max. Delta arcsec=0.216606 | Result=PASS | Source B=121,927 | Package B=758,208 | Toolchain=.NET SDK 8.0.423 Row: Language=Factor | Max. Delta arcsec=51.049773 | Result=PASS | Source B=43,312 | Package B=493,140 | Toolchain=Factor 0.101 Row: Language=Fantom | Max. Delta arcsec=0.238317 | Result=PASS | Source B=54,847 | Package B=549,148 | Toolchain=Fantom 1.0.83 Row: Language=Fortran | Max. Delta arcsec=0.226948 | Result=PASS | Source B=51,037 | Package B=495,006 | Toolchain=GNU Fortran 16.1.0 Row: Language=FreeBASIC | Max. Delta arcsec=0.252308 | Result=PASS | Source B=66,512 | Package B=580,763 | Toolchain=FreeBASIC 1.10.1 Row: Language=GNU Octave | Max. Delta arcsec=38.034360 | Result=PASS | Source B=35,427 | Package B=503,786 | Toolchain=GNU Octave 11.3.0 Row: Language=Go | Max. Delta arcsec=0.239381 | Result=PASS | Source B=39,667 | Package B=526,531 | Toolchain=Go 1.26.5 Row: Language=Groovy | Max. Delta arcsec=2.810988 | Result=PASS | Source B=47,731 | Package B=586,421 | Toolchain=Apache Groovy 5.0.2 / OpenJDK Row: Language=Haskell | Max. Delta arcsec=0.259614 | Result=PASS | Source B=44,580 | Package B=498,045 | Toolchain=GHC 9.10.3 Row: Language=Haxe | Max. Delta arcsec=0.228185 | Result=PASS | Source B=46,913 | Package B=533,441 | Toolchain=Haxe 4.3.7 Row: Language=Java | Max. Delta arcsec=0.238317 | Result=PASS | Source B=46,825 | Package B=548,599 | Toolchain=Microsoft OpenJDK 25.0.3 Row: Language=JavaScript | Max. Delta arcsec=0.236219 | Result=PASS | Source B=107,767 | Package B=592,039 | Toolchain=Node.js 24.15.0 / Browser ES Modules Row: Language=Julia | Max. Delta arcsec=0.229764 | Result=PASS | Source B=30,958 | Package B=477,282 | Toolchain=Julia 1.12.6 Row: Language=Kotlin | Max. Delta arcsec=0.238317 | Result=PASS | Source B=39,887 | Package B=505,280 | Toolchain=Kotlin 2.4.10 / OpenJDK Row: Language=Lua | Max. Delta arcsec=0.216606 | Result=PASS | Source B=41,719 | Package B=521,245 | Toolchain=Lua 5.4 Row: Language=Nim | Max. Delta arcsec=0.228185 | Result=PASS | Source B=38,024 | Package B=520,143 | Toolchain=Nim 2.2.10 Row: Language=OCaml | Max. Delta arcsec=0.232382 | Result=PASS | Source B=119,362 | Package B=724,314 | Toolchain=OCaml 5.4.0 Row: Language=Perl | Max. Delta arcsec=0.236719 | Result=PASS | Source B=43,107 | Package B=469,668 | Toolchain=Perl 5 Row: Language=PHP | Max. Delta arcsec=0.232031 | Result=PASS | Source B=33,017 | Package B=516,442 | Toolchain=PHP 8.3.30 CLI Row: Language=PowerShell | Max. Delta arcsec=37.997961 | Result=PASS | Source B=49,973 | Package B=470,165 | Toolchain=PowerShell 7.6.4 Row: Language=Prolog | Max. Delta arcsec=38.032226 | Result=PASS | Source B=55,733 | Package B=632,243 | Toolchain=SWI-Prolog 10.0.2 Row: Language=Python | Max. Delta arcsec=0.082129 | Result=PASS | Source B=218,903 | Package B=787,360 | Toolchain=Python 3.11.9 Row: Language=R | Max. Delta arcsec=0.231526 | Result=PASS | Source B=33,980 | Package B=506,812 | Toolchain=R 4.6.1 Row: Language=Racket | Max. Delta arcsec=0.218560 | Result=PASS | Source B=44,652 | Package B=482,854 | Toolchain=Racket 9.2 Row: Language=Ruby | Max. Delta arcsec=0.238317 | Result=PASS | Source B=37,165 | Package B=506,816 | Toolchain=Ruby 3.4 Row: Language=Rust | Max. Delta arcsec=0.228185 | Result=PASS | Source B=49,635 | Package B=541,242 | Toolchain=rustc 1.94.1 Row: Language=Scala | Max. Delta arcsec=0.238317 | Result=PASS | Source B=43,107 | Package B=499,504 | Toolchain=Scala CLI 1.15.0 / OpenJDK Row: Language=Smalltalk | Max. Delta arcsec=42.792737 | Result=PASS | Source B=34,747 | Package B=422,800 | Toolchain=Pharo 12 Row: Language=Squirrel | Max. Delta arcsec=0.228185 | Result=PASS | Source B=44,919 | Package B=530,616 | Toolchain=Squirrel 3 with float64 build Row: Language=Tcl | Max. Delta arcsec=0.232382 | Result=PASS | Source B=47,620 | Package B=468,744 | Toolchain=Tcl 8.6 Row: Language=TypeScript + WebAssembly | Max. Delta arcsec=0.239511 | Result=PASS | Source B=57,170 | Package B=555,531 | Toolchain=TypeScript 7.0.2, Rust WASI, Node.js 24.15.0 Row: Language=V | Max. Delta arcsec=0.236584 | Result=PASS | Source B=40,341 | Package B=507,133 | Toolchain=V 0.4 Row: Language=Vala/Genie | Max. Delta arcsec=0.228185 | Result=PASS | Source B=74,030 | Package B=589,922 | Toolchain=Vala 0.56 Row: Language=Visual Basic .NET | Max. Delta arcsec=0.232031 | Result=PASS | Source B=102,111 | Package B=650,099 | Toolchain=.NET SDK 8.0.423 Row: Language=Zig | Max. Delta arcsec=0.239824 | Result=PASS | Source B=44,555 | Package B=524,110 | Toolchain=Zig 0.16.0 A.2 Performance, fastest first ------------------------------ Factor 1.000 denotes the fastest median in the validation run. Columns: Rank | Language | Minimum ms | Median ms | Maximum ms | Factor Row: Rank=1 | Language=TypeScript + WebAssembly | Minimum ms=597.377 | Median ms=700.999 | Maximum ms=1047.449 | Factor=1.000 Row: Rank=2 | Language=Fortran | Minimum ms=596.688 | Median ms=750.360 | Maximum ms=1158.344 | Factor=1.070 Row: Rank=3 | Language=Rust | Minimum ms=523.705 | Median ms=823.898 | Maximum ms=1294.582 | Factor=1.175 Row: Rank=4 | Language=B4X | Minimum ms=775.000 | Median ms=971.000 | Maximum ms=2194.000 | Factor=1.385 Row: Rank=5 | Language=Haxe | Minimum ms=39.747 | Median ms=1077.578 | Maximum ms=2013.806 | Factor=1.537 Row: Rank=6 | Language=Delphi/Object Pascal | Minimum ms=937.000 | Median ms=1078.000 | Maximum ms=1672.000 | Factor=1.538 Row: Rank=7 | Language=Zig | Minimum ms=1035.454 | Median ms=1160.447 | Maximum ms=2320.055 | Factor=1.655 Row: Rank=8 | Language=C++ | Minimum ms=1223.592 | Median ms=1441.870 | Maximum ms=2671.024 | Factor=2.057 Row: Rank=9 | Language=Java | Minimum ms=1284.711 | Median ms=1458.187 | Maximum ms=3353.160 | Factor=2.080 Row: Rank=10 | Language=C | Minimum ms=1343.938 | Median ms=1486.065 | Maximum ms=3056.110 | Factor=2.120 Row: Rank=11 | Language=Kotlin | Minimum ms=1176.612 | Median ms=1593.443 | Maximum ms=5530.074 | Factor=2.273 Row: Rank=12 | Language=Ada | Minimum ms=1460.014 | Median ms=1640.974 | Maximum ms=3057.029 | Factor=2.341 Row: Rank=13 | Language=V | Minimum ms=1575.736 | Median ms=1878.741 | Maximum ms=2571.347 | Factor=2.680 Row: Rank=14 | Language=D | Minimum ms=1546.526 | Median ms=1890.757 | Maximum ms=4220.870 | Factor=2.697 Row: Rank=15 | Language=Go | Minimum ms=1468.523 | Median ms=2141.171 | Maximum ms=9256.961 | Factor=3.054 Row: Rank=16 | Language=Visual Basic .NET | Minimum ms=1696.939 | Median ms=2216.958 | Maximum ms=3742.810 | Factor=3.163 Row: Rank=17 | Language=F# | Minimum ms=1783.725 | Median ms=2231.113 | Maximum ms=3564.241 | Factor=3.183 Row: Rank=18 | Language=Nim | Minimum ms=2119.599 | Median ms=2326.564 | Maximum ms=5060.611 | Factor=3.319 Row: Rank=19 | Language=C# | Minimum ms=2374.419 | Median ms=2552.401 | Maximum ms=6731.288 | Factor=3.641 Row: Rank=20 | Language=Dart | Minimum ms=2190.595 | Median ms=2733.704 | Maximum ms=5027.791 | Factor=3.900 Row: Rank=21 | Language=Scala | Minimum ms=2073.900 | Median ms=3242.849 | Maximum ms=7436.041 | Factor=4.626 Row: Rank=22 | Language=OCaml | Minimum ms=2669.212 | Median ms=3467.746 | Maximum ms=8892.401 | Factor=4.947 Row: Rank=23 | Language=FreeBASIC | Minimum ms=2767.911 | Median ms=3570.477 | Maximum ms=5810.864 | Factor=5.093 Row: Rank=24 | Language=Julia | Minimum ms=3434.719 | Median ms=4304.078 | Maximum ms=8335.834 | Factor=6.140 Row: Rank=25 | Language=Fantom | Minimum ms=4241.671 | Median ms=5794.304 | Maximum ms=8545.390 | Factor=8.266 Row: Rank=26 | Language=Vala/Genie | Minimum ms=4412.042 | Median ms=5820.308 | Maximum ms=8666.353 | Factor=8.303 Row: Rank=27 | Language=Haskell | Minimum ms=6047.352 | Median ms=8690.853 | Maximum ms=14693.710 | Factor=12.398 Row: Rank=28 | Language=BlitzMax | Minimum ms=7899.000 | Median ms=8742.000 | Maximum ms=12931.000 | Factor=12.471 Row: Rank=29 | Language=JavaScript | Minimum ms=7724.900 | Median ms=10157.720 | Maximum ms=23217.210 | Factor=14.490 Row: Rank=30 | Language=Common Lisp | Minimum ms=11056.269 | Median ms=14392.095 | Maximum ms=22933.360 | Factor=20.531 Row: Rank=31 | Language=Ballerina | Minimum ms=12341.616 | Median ms=16894.464 | Maximum ms=33663.612 | Factor=24.101 Row: Rank=32 | Language=Racket | Minimum ms=16694.584 | Median ms=21229.729 | Maximum ms=44060.672 | Factor=30.285 Row: Rank=33 | Language=Erlang | Minimum ms=19354.829 | Median ms=24802.406 | Maximum ms=45274.726 | Factor=35.381 Row: Rank=34 | Language=Elixir | Minimum ms=23434.035 | Median ms=29699.584 | Maximum ms=53299.712 | Factor=42.367 Row: Rank=35 | Language=PHP | Minimum ms=41451.985 | Median ms=49798.621 | Maximum ms=104949.488 | Factor=71.039 Row: Rank=36 | Language=Prolog | Minimum ms=49043.000 | Median ms=69317.000 | Maximum ms=255244.000 | Factor=98.883 Row: Rank=37 | Language=Lua | Minimum ms=53249.000 | Median ms=69977.000 | Maximum ms=130427.000 | Factor=99.825 Row: Rank=38 | Language=Squirrel | Minimum ms=55843.000 | Median ms=71891.000 | Maximum ms=119351.000 | Factor=102.555 Row: Rank=39 | Language=Clojure | Minimum ms=55241.707 | Median ms=72206.563 | Maximum ms=171065.047 | Factor=103.005 Row: Rank=40 | Language=Ruby | Minimum ms=66049.112 | Median ms=90263.925 | Maximum ms=168102.051 | Factor=128.765 Row: Rank=41 | Language=Factor | Minimum ms=70004.415 | Median ms=94462.332 | Maximum ms=151220.285 | Factor=134.754 Row: Rank=42 | Language=Smalltalk | Minimum ms=65113.000 | Median ms=95089.000 | Maximum ms=157550.000 | Factor=135.648 Row: Rank=43 | Language=Groovy | Minimum ms=68129.578 | Median ms=95282.139 | Maximum ms=143061.528 | Factor=135.923 Row: Rank=44 | Language=Python | Minimum ms=74058.281 | Median ms=138890.584 | Maximum ms=308314.450 | Factor=198.132 Row: Rank=45 | Language=Perl | Minimum ms=108115.457 | Median ms=154930.755 | Maximum ms=276448.215 | Factor=221.014 Row: Rank=46 | Language=PowerShell | Minimum ms=206315.845 | Median ms=250942.054 | Maximum ms=717706.460 | Factor=357.978 Row: Rank=47 | Language=Tcl | Minimum ms=202078.602 | Median ms=265143.768 | Maximum ms=494701.078 | Factor=378.237 Row: Rank=48 | Language=R | Minimum ms=168780.000 | Median ms=343730.000 | Maximum ms=910730.000 | Factor=490.343 Row: Rank=49 | Language=GNU Octave | Minimum ms=315324.607 | Median ms=419255.178 | Maximum ms=922894.954 | Factor=598.082 Appendix B. Licence boundary ============================ The project-written numerical core, generators and documentation covered by LICENSE-SCOPE.md are under Apache License 2.0. Data tables, external ephemerides, JPL kernels and third-party programs require separate assessment. Redistribution must include LICENSE and NOTICE, preserve copyright and licence notices, and identify modified files. The patent grant and termination rule are stated in section 3 of the Apache licence. Project website: https://www.jostjahn.de/amrum-software/ephemeris/