2026年7月30日木曜日

満月の高さ

子供の頃から, 夏の月は低く, 冬の月は高いと知っていた. 太陽について いえば, 夏の太陽は高く, 冬の太陽は低い. なぜ反対なのか. 私は小学校 高学年のころ, 原田三夫「子供の天文学」が愛読書で, 天文学の基本的な ことは知っていたが, 月の高さについてはよく分らなかった. 直感的にか 出任せにかさかしらにかは知らないが, 理由は「太陽を見るのは昼で, 月 を見るのは夜でだから」と説明していた.

それから何十年の経った今から3年前の学士会会報(No.962, 2023-V)に, 国立天文台(当時, 現在は京都産業大学神山宇宙科学研究所長)の渡部潤一 さんが「中秋の名月」なる一文を寄稿されていて, それに下のような図が あった. (この図は学士会会報の図を見ながら, 私がPostScriptで描き直 した.) 図ではしっかりと冬至の満月は高く, 夏至の満月は低いと説明さ れている. そうなると, 私もこのことを確信したくなった. これまできち んと調べなかったのは, 月の軌道である白道が, 太陽の軌道である黄道と 交差していることから, 月の位置は捉え処がなく, どう動くか調べようも ないだろうと思っていたところ, 確信を以って「夏至の満月は低い」とあっ たので, 自分でも調べてみる気分になった.

手初めに, 天球に於ける月の軌道を描くことにした. 月の位置の赤経赤緯 の表は, 理科年表や天文年鑑にあるが, 紙に印刷してあるから取り出して データとして使うことは出来ない. しかしネット上には国立天文台の 「暦象年表」のページがあり, そこから2026年の毎日の太陽と月の赤経赤 緯を取り込むことが出来る. これを利用して, 太陽と月の軌道を図に描く ことにした.

暦象年表とは, 理科年表の暦部のことである. 私も詳しいことは覚えてい ないが, 終戦の頃やその後の数年は理科年表は刊行されず, 暦象年表が市 販された. 理科年表は暦部の他は毎年殆んど同じ内容なので, 必要なのは 暦象年表だけである. しかし数年経つと, 理科年表が刊行されるようにな り, 暦象年表は書店から姿を消した.

ところがある時, どこかの天文台で, 思いがけなく暦象年表を見付た. 一 般への市販はなくなったが, 天文屋さんのためには出版されていたらしい. そうこうするうちに, 暦象年表はインターネットで見られるようになっ た. ありがたいことである. (有料だが, 理科年表もインターネットで見 ることが出来る.)

この図は時間とは無関係に, 黄道(赤の曲線)と白道(青の曲線)の天球にお ける位置の動きを示す. 赤線の右端は, 黄道が赤経0hの時(春分点の時)の 赤緯は0°で, 右から1/4は, 黄道が赤経6hの時(夏至の時)の赤緯は +23.5°であるのように見る. 白道についても同じ. ただ白道の線は, 14本 くらいが殆んど重なっている.

曲線上にある点は, 暦の各月の満月の日に於ける赤経と赤緯の位置を示す. 5が2回あるのは, 5月に満月が2回あったからだ. これを見ると, 同じ暦 の月の満月は太陽と丁度12時間ずれていることも分る.

これで判明したのは, 交差角が5°とはいえ, 白道は殆んど黄道と一致して いることだった.

この図からの結論をいえば, 太陽と新月の月は, その赤経と赤緯は同じで, 満月の月の赤経は12hずれ, 赤緯は南北反対だが, 絶対値は同じというこ とである. 従って夏至の満月は, 太陽が天の赤道の上, 23.5°の高いとこ ろで南中するのに対し, 月は天の赤道の下, 23.5°低いところで南中する. 冬至はその反対である. 目出度し目出度し.

今回の検討は, 私にもうひとつの宿題の解答も与えた. それは1960年かそ の少し後だっと思うが, 物理学科の何年か後輩の佐々木不可止君がスェー デンの大学の留学を終えて帰国し, 私のところへ来て雑談していた時のこ とだ. 佐々木君はこういった. 「スェーデンのような高緯度の所では, 月 が北の空に出る.」この話はそれだけで, 私は北極圏では白夜に太陽が沈 まないように, 月も地平線に沿って回るからだろうと考えたが, それ以上 はまたいつか考えようという程度であった.

このブログの最初にあった図は, 東京あたりの北緯35°くらいを想定して 描いてある. それより赤道に近い方では, 地軸がもっと寝て, 満月の軌道 はもっと起きる. 反対に極に近くを考えると, 地軸は立って, 満月の軌道 は水平になり, 春分・秋分の満月の軌道は水平線のところに来る. 冬至の 満月は地上23.5°のあたりで東→南→西→北→と周回す るようになるから, 北の空を通ることもあるわけだ.

佐々木君は大学院が終わると, 北海道大学に就職し, 理学部化学科の教授 だった. 北大を定年で退職し, 他の私大に移ったが, 間も無く病没し た.

佐々木君は学部生の頃にも高橋研に出入りし, パラメトロン回路にも興味 をもっていた. 佐々木君の考えた閾値の論理回路の驚くべき式は, Knuth がThe Art of Computer Programming, 第4A巻の7.1.15項の「対称的Boole 関数」に紹介した.

2026年7月11日土曜日

マージソート

昨今のことは存ぜぬが, かつての計算機科学科での必須の科目は, 計算機 のアーキテクチャとアルゴリズムであった. しかし最近のパソコンの中は 当時のアーキテクチャとは掛け離れて複雑になり, プログラムを書いて計 算するよりも, 情報端末として使われている. アルゴリズムを勉強しても 使う機会はない.

ところで突然マージソートのプログラムを書くことになった. マージソート に関しては大体のことは理解している心算りであったが, TAOCPの5.2.4項 を眺めたら, 意外と巧妙なことをやっているらしい. しかし, TAOCPのプ ログラムは例によって自然言語で書いてあり, 読む気にもならない. 私と しては, 再帰プログラムでさっさと書けるのではないかと思い立ち, やっ てみたのがこのブログである.

とりさえずマージソートの核心部分のおさらいから. 下の図にはA, B, Cの 3つの図がある, 似たような絵はTAOCPにあり, データの数値もそこから 借用した.

まずAを見よう. 左方のs0とs1は既にソート済みの数列である. どちらも 左の小さい値のある方が先頭である. これをマージして右方の数列t0を作る. まず先頭の503と87を比べ, 小さい方, 87をs1から外して, それまで空の列で あったt0に移す. s1は512が先頭になる. 再び先頭同士を比べ, 小さい方, 503をt0へ移す, 今度は703と512を比べ, 512がt0へ移る. 次はs1の 677がt1へ行き, s1は空になる. このように比べている数列の一方が空に なったら, もう一方の残りの数列をすべてt0へ移す. するとs0, s1は共に 空になり, すべての数はソートされてt0へ移動した. マージソートは元の 数列のソートされたと見える部分列を2つずつマージし, 最後は1つの数列に なるまで繰り返す.

その手順の最初が図Bで, 最後が図Cである. まずBから. 上の列が与えられた ソートすべきデータ列である. 下の列は部分的にマージされた列で, 元の数列と同じ 長さの領域を別に用意する.

マージされる2つの数列は, 上の数列の両端から, s0とs1で示すように内側に向って 段々大きくなるように並んでいると考える. ソートされた列の終は次の数値が今の数値より小さく なるところである. 図では縦線で示した. 上の数列の左からをs0, 右からをs1とし, これをマージして用意した領域の左からt0として詰める.

s0とs1とでt0が出来たら, 続いてs0の内側のs2と, s1の内側のs3をマージし, t0を作った領域の, 今度は右端からt1として詰めていく. こうして行くとそのうち, 比べる べき数が同じ場所になり, tの領域も中程に1個所, 空地が残った状態になり, その残った数を空地に移すとこの回のマージは終了する.

次はこうして得られたtの数列を出発側にし, また同じようなマージを繰り返す. その 内, 図Cのように, 同じ数(この図では中程の908)を比べる状態になり, tの 領域の唯一の空地が右端に残り, そこに908を移動してソートは終了する.

後はこれを正直にプログラムにすることだ. Schemeで書いたのがこれである. 関数名がalgorithm524nなのは, TAOCPのAlgorithm524Nを書き換えたから である. 引数のrはソートすべき数列.

すぐにtwowaymergesortというサブルーチンがある. これは図BやCの1回のsからtへの マージである. 引数のrsはs(source)の数列. その長さがnで, その長さのt(target)の 数列の場所. Schemeではリストの要素を取るのに, list-refのように長い関数名を 書かなくてはならないので, 数列rsの添字iを取り出す関数rや, sのi番目をtのl 番目に移動するmoveなど, よく使う関数(手続き)を用意する. (MIT Scheme にはどういう訳かlist-set!がないので, 自分で定義して使っている.)

let文は次に使うsの左の場所の添字i, 右の添字j, tの左の添字k, 右の添字lを 初期化する.

次にtoleftとtorightがあるが, 新しい領域の左にあるtへ移すか右にあるtの 移すかで使い分ける. その夫々にfromleftとfromrightがある. これは 比較の一方が空になった後, もう一方の残りをどちらのsから移動するか で使い分ける.

(define (algorithm524n r)
 (define (twowaymergesort rs)
 (let* ((n (length rs))(rt (make-list n '())))
  (define (r i) (list-ref rs i))
  (define (move l i) (list-set! rt l (r i)))
  (define (less? a b) (let ((rsa (r a)) (rsb (r b)))
    (< rsa rsb)))
  (let ((i 0) (j (- n 1)) (k 0) (l (- n 1)))
    (define (toleft)
      (define (fromright) 
        (move k j)(set! j (- j 1))(set! k (+ k 1))
        (if (less? j (+ j 1))(toright)(fromright)))
      (define (fromleft)
        (move k i)(set! i (+ i 1))(set! k (+ k 1))
        (if (less? (- i 1) i)(fromleft)(toright)))
      (if (= i j) (begin (move k i)
        (if (< k (- n 1))(twowaymergesort rt) rt))
        (if (less? i j) 
          (begin (move k i)
            (set! i (+ i 1)) (set! k (+  k 1))
	    (if (less? (- i 1) i)
	      (toleft) (fromright)))
	  (begin (move k j)
	    (set! j (- j 1)) (set! k (+ k 1))
	    (if (less? j (+ j 1))
	      (fromleft) (toleft))))))
    (define (toright) 
      (define (fromright) 
        (move l j)(set! j (- j 1))(set! l (- l 1))
        (if (less? j (+ j 1))(toleft)(fromright)))
      (define (fromleft) 
        (move l i)(set! i (+ i 1))(set! l (- l 1))
        (if (less? (- i 1) i)(fromleft)(toleft)))
          (if (= i j) (begin (move l i)
	    (twowaymergesort rt))
      (if (less? i j)
	  (begin (move l i)
	    (set! i (+ i 1)) (set! l (- l 1))
	    (if (less? (- i 1) i)
	       (toright) (fromright)))
	  (begin (move l j)
	    (set! j (- j 1)) (set! l (- l 1))
	    (if (less? j (+ j 1))
	      (fromleft) (toright))))))
    (toleft))))
(twowaymergesort r))

(algorithm524n
  '(503  87 512  61 908 170 897 275
    653 426 154 509 612 677 765 703))
TAOCPには, merge sortは1945年頃, John von Neumannが提案したと 書いてある.