緊急告知

astrob.cpp において、計算ミスが発覚しました。
方位角の計算にミスがありました。ただ、計算対象の天体(ここでは、太陽か月)が、地平線近くにあるときは、たまたま、かなり良い結果になります。
(誤差が2度以内)
しかし、高度が大きくなるに従って、誤差が大きくなってきます。

2010/06/21 以前に astrob.cpp をダウンロードされた方は、再度ダウンロードをお願いします。

はじめに

Twitter 用の Bot で、日の出・日の入り・夜明け(明六ツ)・日暮れ(暮六ツ)・月の出・月の入りの算出をしています。
ここでは、そのために使用してるプログラムをご紹介いたします。

プログラムは、2系統があります。
・『新こよみ便利帳』(暦計算研究会編,恒星社厚生閣)をベースにしたもの
・『日の出・日の入りの計算』(長沢工著,地人書館)をベースにしたもの
以上です。
ここでは、それぞれのプログラムを紹介いたします。

『新こよみ便利帳』によるもの

該当書籍の、「日の出・日の入り算出プログラム」(オリジナルは Basic)を、C++ に書き直して、さらに、読み出しのインターフェイスを改造したものです。
当初、「何もわからずにC++に焼き直しただけ」というものでしたが、他のプログラムを見るうちに、全体の流れがわかってきました。
このため、かなり書き換えて、C++ 風のプログラムにしあげてあります。

ソースファイル
ヘッダファイル
テスト用のメイン
です。

deiri getHinodeHinoiri(std::tm today, ido_keido here, double jisa = 9);
deiri getAkeKure(std::tm today, ido_keido here, double jisa = 9);
という関数を呼び出すことで、today に指定した日の、here で指定した緯度・経度の場所の、現地時間(協定世界時との時差 jisa)での日の出・日の入り(getHinodeHinoiri())、夜明け・日暮れ(getAkeKure())が求まります。
tm 構造体の、tm_year や、tm_mon の設定が、一見不自然ですが、tm 構造体の定義(年は、1900 年始まり、月は 0 始まり)に準じたものです。

プログラムの流れは、太陽の黄経を求める → それを、赤経・赤緯に変換する → 高度を求める → 日の出・日の出・日の入りの判定条件にマッチするように、時刻を調整するというものです。
この流れ自体は標準的なものですが、太陽の黄経決定を非常に短いプログラムで実現しています。
簡単な計算で求めている割には、精度は非常によくて、おおむね、1分以内の誤差に収まっています。
時々、2分近い誤差もみられますが、2分に達することはないようです。

『日の出・日の入りの計算』によるもの

ソースファイル
ヘッダファイル
です。

こちらのプログラムは、様々な補正を行っており、前者よりもさらによい精度で計算が可能です。
プログラムの流れは、前者と同様ですが、たとえば、日の出判定の高度算出にも、その時点の太陽の距離(これが変わると、見かけの太陽の大きさが変わる)も反映したものになっています。
おおむね、1分以内の精度で計算可能です。
また、太陽の黄経も、非常に精度よく求められており、二十四節気の基準となる太陽位置なども、1分ちょっとの誤差で収まっています。

ただし、こちらのほうは、「日付」や「時刻」の表現に、Turbo C++ や、C++ Builder で使われている、TDateTime を使用しており、これに依存しています。
そのため、これがある処理系だとそのまま使えますが、そうでなければ、この点は変更が必要です。

プログラム作成に当たって、全体を、C++のクラスが持っている、「継承」の仕掛けでまとめてあります。
ベースクラスである、astro がすべての計算方法を知っている。計算に必要なロジックが、sun と moon で違っている場合、それは、仮想関数を使って解決します。
実際、astro で具体的に定義されているのは、黄経・黄緯 → 赤経・赤緯の計算など、論理的な計算式。
一方、各天体の、黄経・黄緯の計算は、それぞれの天体で個別に定義をすることになります。

それぞれ、TDateTime now = TDateTime(2010, 3, 1) + TDateTime(12, 23, 31, 0); // 2010年3月1日 12時23分31秒(000ms)
などと定義した上で、
astro::ido_keido koudou = sun(now).koudou_axis(); // 黄道座標を得る
double koukei = sun(now).kouduo_axis().keido; // (分離して)黄経を得る
double koui = sun(now).kouduo_axis().ido; // (分離して)黄緯を得る
などとできます。赤経・赤緯,時角なども同様です。

日の出・日の入りなどの時刻は、
astro ido_keido here;
here.ido = (ここに緯度・度単位);
here.keido = (ここに経度・度単位);
TDateTime today = TDateTime(2010, 3, 1);
として、

sun(today).de(here); // 日の出
sun(today).iri(here); // 日の入り
sun(today).ake(here); // 夜明け(明六ツ)
sun(today).kure(here); // 日暮れ(暮六ツ)

moon(today).de(here); // 月の出
moon(today).iri(here); // 月の入り
となります。

構造的に大きく変わったのは、月相・月齢の算出関数です。
これらは、「月の属性」と考えていたのですが、計算上は、「太陽と月の相互関係」ですので、これを、sun_moon という別のクラスに分離しました。
sun_moon(now).phase() で月相が、sun_moon(now).age() で月齢が求められます。

テストプログラムというか、使用法の案内をかねて、MoonClock というのを作成してみました。

こんな感じで、いろいろと表示します。

実行ファイル
プロジェクトファイル(ソースファイルも)
です。
プロジェクトファイルには、astrob.h, astrob.cpp が含まれませんので、別途ダウンロードして同じフォルダにコピーしていただければ、Turbo C++ でビルド可能なはずです


Nagi -- from Yurihama, Tottori, Japan.
E-mail:k1@axis.blue