計算方法
求める年の範囲を絞って、次の大雑把な式
春分 = 経過年数 × 太陽年 + 過去の春分
秋分 = 経過年数 × 太陽年 + 過去の秋分
を用います。
注意:目安の算出なので、国立天文台が発表する正式な日付を確認してください。
太陽年
手元にある、天文年艦 2020 (天文基礎データ) によると
$365日5^h48^m45^s.142$
とあります。これは
$365 + \frac{20925.142}{86400.000} = 365.242189143\dot{5}1\dot{8}$
ですが、浮動小数点演算は使いたくないので、日単位の小数部を 16bit として
$20925.142 \div 86400 \times 2^{16} \fallingdotseq 15872$
$15872 \div 2^{16} = 0.2421875$
この値で妥協します。
春分と秋分
手元にある、理科年表 2017 (暦部、二十四節気)によると
春分 3月20日19時29分
秋分 9月23日05時20分
とあります。これを基点にして、2030年まで計算してみます。
サンプル プログラム
通日の処理では「メモ:年月日と通日を自前で変換」を使っています。
/*
* 太陽年の小数部: 15872 = 0.2421875 * (1<<16)
*/
static unsigned int base_vernal_days = 0; /* 基点となる「春分の日」の通日 */
static unsigned int base_vernal_frac = 0; /* 基点となる「春分の日」の小数部 */
unsigned int vernal_equinox(unsigned int nY)
{
return ((nY * 365 + base_vernal_days) +
((nY * 15872 + base_vernal_frac) >> 16));
}
static unsigned int base_autumn_days = 0; /* 基点となる「秋分の日」の通日 */
static unsigned int base_autumn_frac = 0; /* 基点となる「秋分の日」の小数部 */
unsigned int autumn_equinox(unsigned int nY)
{
return ((nY * 365 + base_autumn_days) +
((nY * 15872 + base_autumn_frac) >> 16));
}
int main()
{
unsigned int vY, vM, vD, vT;
unsigned int aY, aM, aD, aT;
unsigned int n;
/* 春分の基点を求める */
base_vernal_days = ymd2t(2017, 3, 20);
base_vernal_frac = (19*60+29)*65536/(24*60);
/* 秋分の基点を求める */
base_autumn_days = ymd2t(2017, 9, 23);
base_autumn_frac = ( 5*60+20)*65536/(24*60);
/* n = 経過年 */
for (n = 0; n <= 13; n++)
{
vT = vernal_equinox(n);
t2ymd(&vY, &vM, &vD, vT);
aT = autumn_equinox(n);
t2ymd(&aY, &aM, &aD, aT);
printf("%04d/%02d/%02d, %04d/%02d/%02d\n", vY, vM, vD, aY, aM, aD);
}
return 0;
}
実行結果
2017/03/20, 2017/09/23
2018/03/21, 2018/09/23
2019/03/21, 2019/09/23
2020/03/20, 2020/09/22
2021/03/20, 2021/09/23
2022/03/21, 2022/09/23
2023/03/21, 2023/09/23
2024/03/20, 2024/09/22
2025/03/20, 2025/09/23
2026/03/20, 2026/09/23
2027/03/21, 2027/09/23
2028/03/20, 2028/09/22
2029/03/20, 2029/09/23
2030/03/20, 2030/09/23
「国立天文台:質問3-1)何年後かの春分の日・秋分の日はわかるの?」と同じ結果を得られました。しかし、国立天文台の計算は、こちらのサンプル プログラムのような雑な計算ではないでしょう。