多くのソートアルゴリズムの中で、直感的に最も理解しやすいのは、バブルソートといわれている。バブルとは「泡」のことで、並べ替えの過程でデータが下から上へ移動する様子が、泡が浮かんでいくように見えることからこの名前がついたらしい。

<関数名>
  bubbleSort ---- バブル法によるソート

<形式>
  void bubbleSort(DATA *data, int nmem, int asdes);

<引数>
  typedef struct {
    int key;   /* 比較のキーとなるフィールド */
    int info;   /* その他のフィールド */
  } DATA;
  data (入出力) データレコードの配列
  nmem (入力) レコード配列の大きさ
  asdes (入力) 昇順・降順別、0:昇順, 1:降順

<関数値>
  なし

<用例>
  bubbleSort-test.c

<関数本体>
  bubbleSort.c

<説明>
  縦方向一列に並んだレコードの中で、値の小さいレコード(昇進の場合)は軽く、泡(バブル)のように上に浮かんでいく、というようにイメージすれば分かりやすい。
  まず下から全体を走査して、隣接する2つのレコードの大小順序が狂ったとき、2つを入れ換える。この走査で、一番値の小さい(軽い)レコードが1番上に浮かびあがる。つぎに下から上2つ目のレコードまで走査して隣り同士を必要に応じて入れ換えることにより、その中の最小のものが上から2つ目のレコードに浮かびあがる。このように最後のレコードまで繰り返して終了。
  ご利用の際、データ構造を実際の問題に合わせて修正してほしい。

ソート (sort、整列) とは、データをある規則に従って並び替えることをいう。例えば、英語辞書は頭文字のアルファベット順にソートされている。

また数字を小さいものから大きいものに並べることを、昇順という。例: 1, 2, 3, 4, 5。
逆に、大きいものから小さいものまでの並び方を、 降順という。例: 5, 4, 3, 2, 1。

文字になるとややこしくなる。考え方としては、文字の内部コード(コンピュータ内の文字コード、例えばアスキーコードとか)を基準にソートすることが多いが、必ずしも常識と一致しないこともあるので、ご注意を。

なお、漢字のソートとなると、読み方が複数あるので、漢字の代わりに読み方でソートすることがほとんど。ということで、実際のソートは数字以外だと、結構大変。現場のひとによく聞いて、そこのルールに従うしかないかも。

ソートのプログラムに、速度の遅いもの、複雑ですが高速なもの、動きの安定するもの、色々なアルゴリズムが考え出されている。アルゴリズムの良し悪しを考えるのにいい素材になると思う。

プログラマとして食っていくには、多くのアルゴリズムを習得しないといけないし、アルゴリズムの良し悪しをご自分で判断できることも大切。判りやすくて高速なものがあれば万万歳だが、世の中はそうはあまくない。

さて、まずは選択ソートの関数。別名 セレクションソート(Selection Sort)。

<関数名>
  selectSort ---- 選択法によるソート

<形式>
  void selectSort(DATA *data, int nmem, int asdes);

<引数>
  typedef struct {
    int key;   /* 比較のキーとなるフィールド */
    int info;   /* その他のフィールド */
  } DATA;
  data  (入出力) データレコードの配列
  nmem (入力) レコード配列の大きさ
  asdes (入力) 昇順・降順別、0:昇順, 1:降順

<関数値>
  なし

<用例>
  selectSort-test.c

<関数本体>
  selectSort.c

<説明>
  選択ソートでは、まず全体を走査して最小のレコード(昇順の場合) を見つけ、それを最初のレコードと入れ換える。つぎに2つ目のレコードから最後まで走査してその中の最小のものを見つけ、2つ目のレコードと入れ換える。このように最後のレコードまで繰り返して終了。
  ご利用の際、データ構造を実際の問題に合わせて修正してほしい。


日食、黒い太陽ともいう。それを信仰する、黒い太陽教もあると聞く(笑)。

地球からみて、太陽が月の背後に隠された天体現象。地球、月、太陽の相対位置により、皆既食、金環食、部分食の三つあるらしい。

日食は新月のときにしか起きないが、月と地球との軌道面が傾いているため合致する機会が少なく、年数回しか起きない。しかも、月食と違って観測できる場所がきわめて限られる。

本プログラムは日食の時刻を表示してくれる。正しく計算できるかな。

<プログラム本体>
eclipse.c ---- 最大日食の時刻計算

<入力>
求めたい年(西暦年)

<出力>
計算した、最大日食の時刻表示(分まで)

実行例

<注意事項>
関数 solarPos()太陽の位置計算)、および、関数 lunarPos()月の位置計算) が必要。
また、関数 ut2jd()ユリウス日への換算)、jd2ut()ユリウス日からの換算)も必要。

<説明>
年の365(または366)日に対し、太陽と月の黄径をそれぞれ計算し、互いにもっとも近く、さらに、月の黄緯が0に近い時刻、を求める。
なお、日付は日本標準時に修正してある。海外では1日ずれることもある。

日食時刻
2000年 2月 5日 20時25分
7月 2日  8時59分
7月31日  8時 3分
12時26日 2時24分
2001年 6月21日 21時 0分
12月15日 5時49分
2002年 6月11日 8時48分
12月 4日 16時36分
2003年 5月31日 13時22分
11月24日 8時 1分
2004年 4月19日 22時22分
10月14日 11時50分
2005年 4月 9日 5時33分
10月 3日 19時30分
2006年 3月29日 19時17分
9月22日 20時47分
2007年 3月19日 10時53分
9月11日 21時46分
2008年 2月 7日 12時45分
8月 1日 19時14分
2009年 1月26日 16時55分
7月22日 11時36分
2010年 1月15日 16時12分
7月12日  4時42分


太陽、地球、月、の3天体が一直線上にあり、月が地球の影にはいってみえなくなる現象を、月食という。満月のときにのみ起きる。

月食の回数は日食より少ないが、一地点で見える回数は月食のほうが多い。満月のたびに月食が起きないのは、月の軌道面と地球の軌道面が若干傾いているためで、最大年3回しか起きないそうだ。

本プログラムは月食の時刻を教えてくれるもの。果たしてうまくいくか、実際にその日にならないと判らないかな。

<プログラム本体>
lunarEclipse.c ---- 最大月食の時刻計算

<入力>
求めたい年(西暦年)

<出力>
計算した、最大月食の時刻表示(分まで)

実行例

<注意事項>
関数 solarPos()太陽の位置計算)、および、関数 lunarPos()月の位置計算) が必要。
また、関数 ut2jd()ユリウス日への換算)、jd2ut()ユリウス日からの換算)も必要。

<説明>
年の365(または366)日に対し、太陽と月の黄径をそれぞれ計算し、その差が180度にもっとも近く、さらに、月の黄緯が0に近い時刻、を求める。
なお、日付は日本標準時に修正してある。海外では1日ずれることもある。

月食時刻
2000年 1月21日 13時42分
7月16日 22時57分
2001年 1月10日  5時26分
7月 6日  0時 6分
2003年 5月16日 12時37分
11月 9日 10時16分
2004年 5月 5日  5時35分
10月28日 12時10分
2005年10月17日 16時14分
2006年 3月15日 13時36分
9月 8日  8時 7分
2007年 3月 4日  8時18分
8月28日 19時37分
2008年 2月21日 12時31分
8月17日  6時18分
2010年 6月26日 20時31分
12月21日 17時14分

満月とは、真丸に輝く月のこと。地球からみて太陽と反対方向になったときの月。つまり、月の黄径と太陽の黄径との差が180度になったときだ。

満月の夜、なんとなく、ロマンチックに感じるのが私だけかな。

このプログラムでは満月の日を教えてくれる。デートの予約に利用できるかも(笑)。

<プログラム本体>
  fullMoon.c ---- 満月の日の計算

<入力>
  求めたい年(西暦年)
  
<出力>
  計算した、満月の日の画面表示

実行例

<注意事項>
  関数 solarPos()太陽の位置計算)、および、関数 lunarPos()月の位置計算) が必要。
  また、関数 ut2jd()ユリウス日への換算)、jd2ut()ユリウス日からの換算)も必要。

<説明>
  年の365(または366)日に対し、太陽と月の黄径をそれぞれ計算し、その差が180度にもっとも近い日を満月の日とする計算。
  なお、日付は日本標準時に修正してある。海外では1日ずれることもある。
  プログラムをさらに精度よく計算させれば、満月となる時刻まで正確に求められるかも。

  満月の日(2003年版、12回)
  1/18、 2/17、3/18、4/17、5/16、6/14、7/14、8/12、9/11、10/10、11/9、12/9。

  満月の日(2004年版、13回)
  1/8、 2/6、3/7、4/5、5/5、6/3、7/2、8/1、8/30、9/28、10/28、11/27、12/27。

ちなみに、ネット上に 満月カレンダー のようなものは結構見かける。

月が満ち欠けして見えるのは、地球から見て太陽と月の離れる角度が変わり、月の太陽に照らされている部分と照らされない部分の見え方が変わるからだ。

月の黄径と太陽の黄径が一致したとき、月の太陽に照らされる部分が地球からは見えない、そんな状態の月を新月という。太陰暦(旧暦)では新月を含む日を月の第1日としているのがその名の由来。

太陽暦が1年約365日に対して、太陰暦は1年354日。ということで、1年(太陽暦)のなかで、新月の日になるのは、12回か13回。

新月の夜は暗いので、犯罪が多いといわれている。
このプログラムでは新月の日を教えてくれる。占いや犯罪防止に役立つかな(笑)。

すごいプログラムだろう、と自慢したくなるが、太陽と月の位置計算関数があれば大したことでもないはず。

<プログラム本体>
  newMoon.c ---- 新月の日の計算

<入力>
  求めたい年(西暦年)
  
<出力>
  計算した、新月の日(年間12回か13回)の画面表示

実行例

<注意事項>
  関数 solarPos()太陽の位置計算)、および、関数 lunarPos()月の位置計算) が必要。
  また、関数 ut2jd()ユリウス日への換算)、jd2ut()ユリウス日からの換算)も必要。

<説明>
  年の365(または366)日に対し、太陽と月の黄径をそれぞれ計算し、位置がもっとも近い日を新月の日とする計算。
  なお、日付は日本標準時に修正してある。海外では1日ずれることもある。

  新月の日(2003年版、13回)
  1/3、 2/1、3/3、4/2、5/1、5/31、6/30、7/29、8/28、9/26、10/25、11/24、12/23。

  新月の日(2004年版、12回)
  1/22、 2/20、3/21、4/19、5/19、6/18、7/17、8/16、9/14、10/14、11/12、12/12。

月の黄経、黄緯、および地心距離を計算する関数。

こちらについても、資料のデータをそのまま利用しただけなので、意味は理解していない。

<関数名>
  lunarPos ---- 月の黄経、黄緯、および地心距離を計算する

<形式>
  long lunarPos(double *lng, double *lat, long j, double d);

<引数>
  lng (出力)黄経(単位、度)
  lat (出力)黄緯(単位、度)
  j  (入力)世界標準時から換算したユリウス日の整数部分
  d  (入力)世界標準時から換算したユリウス日の小数部分

<関数値>
  地心距離(月・太陽中心間の距離)(単位、キロ・メートル)

<注意事項>
  関数 ut2jd()世界標準時からユリウス日への換算)が必要。
  また標準数学ライブラリ cos() も必要。

用例
  double lng, lat;
  lunarPos(&lng, &lat, 2450266L. 0.5);

<関数本体>
  lunarPos.c

<説明>
  ある時刻の月の黄経・黄緯および地球までの距離を計算する。
  太陽と月の黄経を知ると、新月・満月・上弦・下弦の日時を計算できる。これらは月の黄経と太陽の黄経の差がそれぞれ0度、180度、90度、 270度になる瞬間だから。また、新月時に月の黄緯が0に近い値であれば日食となり、満月時に同様に近い値であれば月食となる。
  なお、日本時間JSTを世界標準時UTに直すには、UT = JST - 9 で計算すればよい。

太陽の黄経、地心距離を計算する関数。

正直にいって、関数が正しいかどうか、よく判らない。ここまで、天文学の知識は持ち合わせていないから。ニュートン力学の凄さを体験できるのは確かのようだ。日食や月食の発生時刻まで計算できるんだから、100年前だったら、神様と呼ばれたに違いない。が、コンピュータはまだ発明されてなかったので、判ってても結局凡人でしかならなかったかも。

<関数名>
  solarPos ---- 太陽の黄経、地心距離の計算

<形式>
  long solarPos(double *lng, long j, double d);

<引数>
  lng (出力)黄経(単位、度)
  j (入力)世界標準時から換算したユリウス日の整数部分
  d (入力)世界標準時から換算したユリウス日の小数部分

<関数値>
  地心距離(地球・太陽中心間の距離)(単位、キロ・メートル)

<注意事項>
  関数 ut2jd()世界標準時からユリウス日への換算)が必要。
  また、標準数学ライブラリ cos() も必要。

用例
  double lng;
  solarPos(&lng, 12450266L, 0.0);

<関数本体>
  solarPos.c

<説明>
  地球から観察すると、太陽は恒星の間の、定まった道の上を動いている。太陽の通る道を黄道という。したがって、太陽の黄緯はほぼ 0。また、黄経の 0 度とは春分点に太陽のいるところ。
  いま使われているグレゴリオ暦では、毎年2月4日立春は黄経315度、 3月21日春分は 0 度、6月22日夏至は90度、8月8日立秋は135度、9月24日秋分は180度、12月22日冬至は270度に太陽が位置するらしい。
  本関数を使うと、ある時刻の太陽の黄経および地球までの距離がわかる。
  なお、日本時間JSTを世界標準時UTに直すには、UT = JST - 9 で計算すればよい。

ある日付に対し、n日後の日付を算出する関数。
nの値をマイナスにすれば、n日前の日付になる。

例えば、2004/8/10 から 5日後の日付は 2004/8/15、といった具合。

<関数名>
  dayAdd ---- n日後の日付を算出する

<形式>
  void dayAdd(int *year2, int *month2, int *day2, int year1, int month1, int day1, int n);

<引数>
  year2, month2, day2 (出力)n日後の日付。西暦年月日。
  year1, month1, day1 (入力)基準となる日付。西暦年月日。
  n (入力)n日後。マイナス値にすれば、n日前になる。

<関数値>
  なし。

<注意事項>
  引数として渡された日付の実在性チェックはしない。
  関数 ut2jd()ユリウス日への換算)が必要。
  関数 jd2ut()ユリウス日からの換算)が必要。

用例
  int year, month, day;
  dayAdd(&year, &month, &day, 2004, 8, 1, 11);

<関数本体>
  dayAdd.c

<説明>
  内部では、基準日をまずユリウス日に換算してから、nの値を足し、最後に西暦年月日に戻す。そんな処理を行う。

前後異なる2つの日付に対し、間の離れた日数(差)を算出する関数。

例えば、2004/8/10 から 2004/8/15 まで の日数(差)は 5日、といった具合。

前後関係はが逆になっていれば、マイナスの結果になる。
例えば、2004/8/15 から 2004/8/10 まで の日数は -5日、との計算結果。

<関数名>
  dayDiff ---- 2つの日付の間の日数を算出する

<形式>
  int dayDiff(int year1, int month1, int day1, int year2, int month2, int day2);

<引数>
  year1, month1, day1 前の日付。西暦年月日。
  year2, month2, day2 後の日付。西暦年月日。

<関数値>
  日数。マイナスの値であれば、日付の前後関係が逆になっていることを示す。

<注意事項>
  引数として渡された日付の実在性チェックはしない。
  関数 ut2jd()ユリウス日への換算)が必要。

用例
  dayDiff(2003, 8, 1, 2004, 9, 11);

<関数本体>
  dayDiff.c

<説明>
  内部では、2つの日付をそれぞれ、ユリウス日に換算してから、差の算出を行う。