반응형

만년력(1583년 이후부터) 알고리즘과 프로그래밍

 

작성. 오상문 (sualchi@daum.net)

최종수정 : 2004년 5월 14일

 

 


-

왜 1583년부터 시작해야 하는가

 

1582년에 그 이전에 사용하던 율리우스력에서 그레고리력 방식으로 변경되었습니다.
그 첫 해에는 오차 수정을 위해 윤달이 두 번(23, 67일)이나 적용되어 다른 해에 비해

년간 일수에 많은 차이가 있습니다.

즉, 그레고리력을 적용하면서 그 동안의 잘못된 날짜 오차를 줄이기 위해 3개월에

해당하는 기간을 두 번이나 삽입하였고, 10월 4일(목)에서 10월 15일(금)로 바로

건너뛰는 등 불규칙한 기간이 있습니다.

 

그레고리력은 윤년(2월 윤달)이 있는 해를 다음과 같은 규칙으로 정했습니다.

 

1) 4년으로 나누어지는 해는 윤달(2월은 29일)이 있다.
2) 그러나 100년으로 나누어지는 해는 윤달이 없다.
3) 그러나 400년으로 나누어지는 해는 윤달이 있다.

 

이 규칙을 만족해야만 그 해가 윤년(2월은 29일)이고
아닌 경우에는 평년(2월은 28일)입니다.

 

앞에서 설명한 내용에 의해 필자는 그레고리력을 적용하는 만년력을 1583년

1월 1일을 기준으로 시작했습니다. 그 이전까지 적용하는 만년력은 좀 더 복잡한

계산을 요하는데 이 부분은 여기에서 다루지 않습니다.

 

[주의] 1583년 이전은 ...

중간 달의 날짜가 중간에 변하기도 했고 윤년 계산 방식에도 차이가 있다.

 


-

요일의 변화 

 

요일은 알다시피
일(SUN), 월(MON), 화(TUE), 수(WED), 목(THU), 금(FRI), 토(SAT)입니다.

 

1년은 365일(평년 기준)이고 일주일(7일) 주기로 돌아간다면 다음 해 1월 1일은

전년도 1월 1일보다 요일이 한 단계 앞으로 나아갑니다.
즉, 전년도 1월 1일이 월요일이라면 다음해 1월 1일은 화요일입니다.


하지만 윤달이 있는 년도에는 하루를 더해야 하므로 두 단계 앞으로 나아갑니다.
즉, 전년도 1월 1일이 월요일이라면 다음해 1월 1일은 수요일이 됩니다.

 

1583년 1월 1일을 기준으로 지정된 해 사이의 평년과 윤년을 구한 다음에

다음 공식을 이용하면 그 해 1월 1일의 요일을 구할 수 있습니다.

 

먼저 각 요일의 순서에 맞게 다음 정수처럼 정의하여 계산에 적용합니다.

 

요일 : 일 = 0, 월 = 1, 화 = 2, 수 = 3, 목 = 4, 금 = 5, 토 = 6 
      (요일을 계산하기 좋게 각 요일을 숫자로 표기합니다.) 

 

1583년 1월 1일의 요일은 X요일이라고 가정하겠습니다.

 

[공식] (X + (( 평년합 X 1 + 윤년합 X 2 ) % 7)) % 7

 

[주의] 2000년 1월 1일의 요일을 구한다면 1999년까지만 계산에 적용함!

 

[설명]
평년에는 1씩 더해주고 윤년에는 2씩 더해줍니다.
7로 나눈 나머지 숫자는 해당 요일의 의미합니다.
계산한 요일을 1583년 1월 1일의 요일에 더하여 다시 7로 나눈 나머지를 구하면
구하려는 해의 1월 1일 요일이 됩니다.

 


-

1583년 1월 1일은 무슨 요일일까요?

 

1583년 1월 1일이 무슨 요일인지 모르더라도 그레고리력 계산법을 알고 있고
현재 알고 있는 어떤 날짜의 요일을 기준으로 역계산할 수 있습니다. 
필자는 2000년 1월 1일(토요일)을 기준으로 하겠습니다.

 

2000년을 기준으로 했으니 1583~1999년의 평년과 윤년을 계산하면 되겠군요.

 

1583~1999까지(1583, 1999년 포함)의 햇수는 몇 년인가요?


417 = 1999 - 1583 + 1

 

윤년은 몇 번 있습니까?

 

1999년까지의 윤년 합에서 1582년까지의 윤년 합을 빼면 되겠군요.
1999년까지의 윤년 합은 다음과 같습니다. (INT는 계산 결과에서 정수 부분만 허용)

 

      = INT(1999/4) - INT(1999/100) + INT(1999/400)
484 = 499 - 19 + 4

 

1582년까지의 윤년 합은 다음과 같습니다.

 

      = INT(1582/4) - INT(1582/100) + INT(1582/400)
383 = 395 - 15 + 3

 

그러므로 1583년부터 1999년까지 있었던 윤년은 101번 있었습니다.

 

101 = 484 - 383

 

이제 기간 417에서 101번의 윤년을 빼면 평년 회수가 나오겠군요.

 

316 = 417 - 101

 

계산 결과에 의마혐 1583년부터 1999년까지 평년은 316년 있었고,

윤년은 101년 있었습니다. 이제 요일 계산으로 들어갑니다.

 

평년에는 요일이 하루씩 앞 당겨지고 윤년에는 이틀씩 앞당겨집니다.

 

518 = 316 X 1 + 101 X 2

 

아하... 518에 해당하는 요일이 앞당겨지는군요.

일주일은 7을 주기로 돌아가므로 이 값을 7로 나눈 나머지를 구합니다.

 

0 = 518 % 7

 

하하, 0이라면 7의 배수로 변화했기에 요일 변화가 없다는 말입니다.
(계산하기 편해졌군요. ^^;;)

 

그렇다면 2000년 1월 1일과 1583년 1월 1일의 요일이 같다는 말입니다.

 

2000년 1월 1일은 요일은? 

컴퓨터 달력으로 찾아보니 토요일이네요.
그렇다면,

1583년 1월 1일

은 요일 변화가 없었으니

토요일

이겠군요.


이 계산이 맞는지 2004년 1월 1일의 요일을 구해서 맞는지 확인해봅시다.
달력에 2004년 1월 1일은 목요일로 나옵니다.

과연 그런지 계산해봅시다.

 

먼저, 1583년부터 2003년(2004년 제외!)까지의 평년과 윤년을 계산해봅니다.

앞에서 1582년까지의 윤년이 383번 있었음을 이미 계산했습니다.

2003년까지의 윤년 합에서 1582년까지의 윤년 합을 빼면 되겠군요.

2003년까지의 윤년 합은 다음과 같습니다. (INT는 계산 결과에서 정수 부분만 허용)

      = INT(2003/4) - INT(2003/100) + INT(2003/400)
485 = 500 - 20 + 5

 

즉, 1583년부터 2003년까지 윤년은 102번 있었습니다.

102 = 485 - 383

 

이제 기간 421(= 2003 - 1583 + 1)에서 102번의 윤년을 빼면 평년 회수가 나오겠군요.

319 = 421 - 102

 

그러므로 1583년부터 1999년까지 평년은 319년이고, 윤년은 102년입니다.

 

이제 요일 계산으로 들어갑니다.
평년에는 요일이 하루씩 앞 당겨지고 윤년에는 이틀씩 앞당겨집니다.

523 = 319 X 1 + 102 X 2

 

이제 523을 7로 나눈 나머지를 보면 요일 변화를 알 수 있습니다.

5 = 523 % 7

결과에 의하면 1583년 1월 1일(토요일)에서 5 단계 앞으로 이동한 요일입니다.
그렇다면 2004년 1월 1일은 목요일이군요.

 

맞습니까?

달력을 살펴보면 2004년 1월 1일이 목요일이었으니 계산한 결과가 맞군요.

 

이젠 만년력 알고리즘에서 요일 문제는 거의 해결한 셈입니다. 

그 해의 날짜에 대해서는 1월 1일 기준으로 요일을 계산하거나
앞 계산 방식에서 추가된 날짜만큼 계산하면 됩니다.


1년 12개월의 날짜 수

------------------

 1월 = 31일
 2월 = 28일 (단, 윤년이면 29일)
 3월 = 31일
 4월 = 30일
 5월 = 31일
 6월 = 30일
 7월 = 31일
 8월 = 31일
 9월 = 30일
10월 = 31일
11월 = 30일
12월 = 31일

 

 

[여담] 역사에서 잊혀진 네로의 달 (발췌: 야후 지식정보)
----------------------------------------------------------------------

율리우스가 브루투스에게 시해된 후 로마 황제로 등극한 이가 아우구스투스 황제이다.
그도 율리우스를 본받아 달력에 이름을 남기려고 했다.
그는 트라키아와 아크림 전투에서 승리를 거둔 것을 기념하기 위해 8월의 본래 명칭을 바꾸었다.
그의 생일은 8월이었는데, 아우구스투수가 8월의 명칭을 바꾼 것은 자신의 생일 달을 기념하려는 의미도 있었다.
그는 이 달의 본래 명칭인 섹스틸리스(Sextilis; 제6번째 달)를 아우구스투스(Augustus)라고 바꾸었다.
더욱이 황제인 자신의 달이 다른 달보다 작으면 황제의 권위가 서지 않는다면서 2월에서 하루를 떼어와 31일의 큰 달로 변경했다.
그러자 1월에서 7월까지는 홀수인 달이 큰 달이 되고, 7월과 8월이 연속해서 큰 달이 됐다.
그리고 8월부터 12월까지는 짝수 달이 큰 달이 됐다.
이 때문에 2월이 다른 달에 비해 유난히 작아져 버렸다.
양력은 태양의 운행에 따라 1년의 길이를 정했지만, 달의 길이는 임의대로 정해졌던 것이다.
그 후, 악명이 높던 네로 황제는 이들을 본 따 4월을 자신의 달인 네로네우스(Neroneus)로 고쳤지만, 네로 황제의 사후에 다시 본래의 명칭으로 되돌아왔다.

------------------------------------------------------------------------

 

 

이제 몇 가지 문제와 풀이를 살펴보겠습니다.

 

2004년 1월 1일이 목요일이라고 했습니다.
(기준은 1583년 1월 1일의 토요일도 가능합니다만...)


[문제 1]

2004년 1월 14일은 무슨 요일입니까?

 

1월 1일과 1월 14일은 13일 차이가 나는군요.
목요일은 앞에서 숫자로 4로 할당했습니다.
날짜 차이를 합치고 7로 나눈 나머지가 바로 요일에 해당하는 숫자입니다.

3 = (4 + 13일) % 7 

3에 해당하는 요일은 수요일입니다.
달력에서 확인해보세요. 수요일 맞습니까? ^o^;;

 

[문제 2]

2004년 2월 1일은 무슨 요일입니까?


1월 1일과 2월 1일은 31일 차이가 나는군요. (1월은 31일까지 있습니다.)

0 = (4 + 31) % 7

0에 해당하는 요일은 일요일입니다.
2004년 2월 1일이 일요일 맞습니까?  ^O^;;


[문제 3]

2004년 2월은 윤달입니까?

 

IF (2004%400 == 0)
   무조건 윤달입니다.
ELSE IF (2004%100 == 0)
   평달입니다.
ELSE IF (2004%4 == 0)
   윤달입니다.
ELSE
   평달입니다.

 

이것을 C 언어 구문으로 정리하면 다음과 같습니다.

 

x = 2004;

if ( !(x%400) || (!(x%100) && (x%4)) )
  윤달입니다;
else
  평달입니다;

 

x에 2004년 값을 대입해볼까요?

 

if ( !(2004%400) || ((2004%100) && !(2004%4)) )
  윤달입니다;
else
  평달입니다;    

 

if 문의 조건식 부분은 다음처럼 크게 둘로 나뉜 것입니다.

1) 400년 주기로 찾아오는 해이면 무조건 윤달로 처리됩니다.
2) 나머지는 4년 주기이면서 100년 주기에 해당하지 않는 해를 윤달로 찾습니다.

 

계산해보니 2004년 2월은 윤달입니다.
달력을 보면 29일짜리 2월이니 윤달 맞습니다. ^^;;


[문제 4]

2004년 5월 5일은 무슨 요일입니까?

 

2004년 1월 1일부터 5월 5일까지의 날짜 차이를 구합니다.

1월 = 31일
2월 = 29일 (계산해보니 윤달이었죠? 그래서 29일)
3월 = 31일
4월 = 30일
5월 = 5일  (5월은 5일까지만 계산)

 

125 = (31 + 29 + 31 + 30 + 5) - 1

 

2004년 1월 1일은 목요일(4에 해당)이므로

요일 = (4 + 125) % 7
    3  = 129 % 7

 

3에 해당하는 요일은 수요일입니다.
달력을 실제로 확인하면 2004년 5월 5일은 수요일입니다.

---------------------------------------------------------

 

이제 만년력 기초와 중요한 알고리즘은 모두 배웠습니다.

남은 부분은 달력 형식에 맞춰 화면에 뿌려주는 작업입니다.
만년력 프로그램 코드는 다음 강좌에 올라갑니다.
(이 때는 만년력의 기초나 알고리즘을 설명하지 않습니다. ^^;; )


 

[참고]

꼭 해당 년도의 1월 1일의 요일을 구해야 할까? ------------------------------------------------------------------

원하는 월일의 요일을 구할 때는 굳이 그해 1월 1일을 기준으로 해야하는 것은 아닙니다.

그러나 일단 1월 1일의 요일을 구하고, 원하는 달의 날짜와의 차이를 이용하여 요일을

알아내는 방법이 알기 쉽습니다. 
미리 배열에 해당 년도 1월 1일의 요일을 구해 담아 놓는 방법도 있을 수 있습니다.
기본 원리만 이해한다면 적용이나 해법은 여러 가지일 수 있다는 말입니다.

------------------------------------------------------------------



알치 오상문.

반응형

+ Recent posts