2008年12月9日火曜日

月齢カレンダー

直前のブログ「月齢カレンダー」の月齢計算で, 「ある定数」の決め方がなんとなく杜撰に思われるので, もう少し説得力ある計算法を考えた.

ある日の正午の月齢は, 直前の新月からの時間である. NAOJのウェブページを見ると, 2008年12月27日21時22分が新月だそうだ. すると12月28日正午までの経過時間は14時間38分. 24時間に対しては0.6097...となり, つまりそれが28日の月齢である.

従って望む日の月齢は, 1朔望月を29日499/940とすると, 望む日のRDから2008年12月28日のRDを引き, その29日499/940の剰余プラス0.6097となる.

(define (rd y m d) ;rdの計算
(let* ((p (lambda (n) (= (modulo y n) 0)))
(q (lambda (n) (quotient y n)))
(s `(0 31 ,(if (if (p 100) (p 400) (p 4)) 29 28)
31 30 31 30 31 31 30 31 30 31)))
(- (+ d (* y 365) (q 4) (q -100) (q 400))
(apply + (list-tail s m)))))

(define (ma y m d) ;月齢の計算
(+ (/ (modulo (* (- (rd y m d) (rd 2008 12 28)) 940)
27759) 940.) 0.6097))

(do ((i 1 (+ i 1))) ((> i 12)) ;1日の月齢表の計算
(display (/ (round (* (ma 2009 i 1) 10)) 10)) (newline))

4.6
6.1
4.5
6.
6.5
8.
8.4
9.9
11.4
11.8
13.3
13.8

一方19年7閏法と有理化した朔望月の求め方は次の通り.

1太陽年=365.242198日
1朔望月=29.530589日
1太陽年から12朔望月を引くと10.875166日

これが1朔望月の何分の何に相当するか知りたいので, この比を連分数展開する.

小数xの連分数をn項とるのに

(define (cf x n)
(if (> n 0)
(let* ((y (/ 1 x)) (z (inexact->exact (truncate y))))
(cons z (cf (- y z) (- n 1)))) '()))
として
(cf (/ 10.875144 29.530589) 10)
を計算すると
(2 1 2 1 1 17 2 2 2 2)
が得られる. 17分の1辺りで棄てることにし,
(define (cf2r l)
(if (null? l) 0
(/ 1 (+ (car l) (cf2r (cdr l))))))
で有理数を計算すると
(cf2r '(2 1 2 1 1))→ 7/19

となり, 余りは1朔望月の7/19であることが分かる. 従って19年に7回閏月を置くのである.

次に19太陽年は 365 1/4日の19倍となる. この時間に朔望月は19×12+7回(つまり235回)あるので,

(/ (* (+ 365 (/ 1 4)) 19) (+ (* 12 19) 7))→ 27759/940
(quotient 27759 940)→29
(modulo 27759 940)→499

すなわち29日499/940となる.

追記 上のような月齢の式を書いたが, 最後に0.6097を足すのはこれまたウンシャンである. その回避法は2つあり, まずは2008年12月28日のRDではなく, 2008年12月27日21時22分のRDを基準にすること. つぎは正午ころに新月のある日を見つけることである. たまたま手元の天文年鑑を見ていたら, 2005年8月5日の新月は12時5分であった. これはしたり! 1日は86400秒であり, 5分は300秒なので, 誤差は無視出来よう. 従って

(define (ma y m d) (/ (modulo
(* (- (rd y m d) (rd 2005 8 5)) 940) 27759) 940.))

はそれほどウンシャンではない式だと思っている.

0 件のコメント: