Talk About Network

Google


Register and Login
Nick
Password
Register create new account Sign up is FREE and you can post replies, new topics, bookmark posts and more!
Recover lost password


Programming > Basic Powerbasic > Easter calculat...
Latest [ Topics | Posts ] Archive Post A New Topic Post a Reply
<< Topic < Post Post 1 of 1 Topic 254 of 276
Post > Topic >>

Easter calculation in the Gregorian Calendar

by "Judson McClendon" <judmc@[EMAIL PROTECTED] > Oct 19, 2007 at 01:46 PM

Years ago I wrote a BASIC program using the Easter calculation algorithm
from Knuth's "Art of Computer Programming," Second Edition, pages
155-156, and later posted it on my website, and probably here as well.
Recently I received an email from Edward Moneo informing me of a glitch
in the Epact calculation that would cause errors for certain years
beginning
with 9006. Knuth pointed out this possibility, but his solution was a bit
cryptic, and I hadn't studied it thoroughly enough at the time. Edward
suggested a fix, and I thought of another. Our discussions prompted me
to research the matter further, and the result is the PB/CC program below
(I'm posting a QuickBASIC/QBASIC version to comp.lang.basic.misc and
microsoft.public.basic.dos), which I thought some of you might like to
see.

The problem in the Epact calculation is that, as years get larger than
about
9000, the Epact can become negative, requiring a correction. I didn't code
Knuth's Epact correction into the program below, but here are all three
versions.

    Uncorrected Epact calculation:
        Epact = (11 * GoldenNo + 20 + LunarCorr - LeapCent) MOD 30

    Knuth's correction:
        Epact = (11 * GoldenNo + 20 + LunarCorr - LeapCent) MOD 30
        IF (Epact < 0) THEN Epact = Epact + 30

    Jud's correction:
        Epact = (11 * GoldenNo + 30020 + LunarCorr - LeapCent) MOD 30

        Note: By adding a sufficiently large multiple of 30 to the
constant 20,
        Epact will not become negative in the target range of years. This
        value was chosen as sufficient for Knuth's suggested test range of
        years = 1583 to 999,999. I like this method because it requires no
        extra memory or time.

    Edward Mateo's correction:
        Epact = (11 * GoldenNo + 20 + LunarCorr - LeapCent)
        Epact = Epact - 30 * INT(Epact / 30)

        Note: To be honest, I'm not sure why Edward's correction works,
        but it does.

The program also contains three other Easter calculation methods, the
'original' Oudin algorithm, a simpler version of Oudin's algorithm by
Claus Tonderings, and Butcher's algorithm. All of the algorithms
return the same values for every year in the range 1 - 999,999,999,
except for certain years between 216 and 1497 that the two Oudin
algorithms disagree with the others. To get that huge range, I used the
PowerBASIC version and changed the variables to QUAD (64bit).
I find it strange that several algorithms could give the same result for
years 1 to  999,999,999 except for certain years between 216 & 1497!
Easters before 1583 predated the Gregorian Calendar, and it is not
likely the Gregorian Calendar will remain unchanged past 4999, at
the latest. :-)  (PB/CC program below)
-- 
Judson McClendon      judmc@[EMAIL PROTECTED]
 (remove zero)
Sun Valley Systems     http://sunvaley.com
"For God so loved the world that He gave His only begotten Son, that
whoever believes in Him should not perish but have everlasting life."

'
'  **************************************************
'  *                                                *
'  *                EasterTest.bas                  *
'  *                                                *
'  *       Tests Easter calculation routines        *
'  *                                                *
'  *              Compile using PB\CC               *
'  *                                                *
'  *              Judson D. McClendon               *
'  *              Sun Valley Systems                *
'  *              4522 Shadow Ridge Pkwy            *
'  *              Pinson, AL 35126-2192             *
'  *                 205-680-0460                   *
'  *                                                *
'  **************************************************
'
#COMPILE EXE
#DIM ALL


'
'  ** Sub & Function Declarations **
'
DECLARE FUNCTION EasterKnuth(Year AS LONG) AS LONG
DECLARE FUNCTION EasterKnuth2(Year AS LONG) AS LONG
DECLARE FUNCTION EasterOudin(Year AS LONG) AS LONG
DECLARE FUNCTION EasterOudin2(Year AS LONG) AS LONG
DECLARE FUNCTION EasterButcher(Year AS LONG) AS LONG


'
'  ** Main Function **
'
FUNCTION PBMAIN() AS LONG
   DIM Year    AS LONG
   DIM Knuth   AS LONG
   DIM Knuth2  AS LONG
   DIM Oudin   AS LONG
   DIM Oudin2  AS LONG
   DIM Butcher AS LONG

   FOR Year = 1583 TO 999999
      Knuth   = EasterKnuth(Year)
      Knuth2  = EasterKnuth2(Year)
      Oudin   = EasterOudin(Year)
      Oudin2  = EasterOudin2(Year)
      Butcher = EasterButcher(Year)

      IF (Knuth <> Knuth2) _
          OR _
         (Knuth <> Oudin) _
          OR _
         (Knuth <> Oudin2) _
          OR _
         (Knuth <> Butcher) THEN
         PRINT USING$("######  K:####  ", Year, Knuth);
         IF (Knuth <> Knuth2) THEN
            PRINT TAB(17); "K2:";
            PRINT USING$("####", Knuth2);
         END IF
         IF (Knuth <> Oudin) THEN
            PRINT TAB(26); "O:";
            PRINT USING$("####", Oudin);
         END IF
         IF (Knuth <> Oudin2) THEN
            PRINT TAB(34); "O2:";
            PRINT USING$("####", Oudin2);
         END IF
         IF (Knuth <> Butcher) THEN
            PRINT TAB(43); "B:";
            PRINT USING$("####", Butcher);
         END IF
         PRINT
      END IF

   NEXT

END FUNCTION


'
'  ** EasterKnuth Function **
'
'  Knuth's algorithm with Jud McClendon's Epact correction
'
FUNCTION EasterKnuth(Year AS LONG) AS LONG
   DIM EasterMonth   AS LONG
   DIM EasterDay     AS LONG
   DIM EasterMMDD    AS LONG

   DIM GoldenNo      AS LONG
   DIM SundayCorr    AS LONG
   DIM Century       AS LONG
   DIM LeapCent      AS LONG
   DIM LunarCorr     AS LONG
   DIM Epact         AS LONG
   DIM FullMoon      AS LONG

   GoldenNo = (Year MOD 19) + 1
   Century = (Year \ 100) + 1
   LeapCent = ((3 * Century) \ 4) - 12
   LunarCorr = ((8 * Century + 5) \ 25) - 5
   SundayCorr = ((5 * Year) \ 4) - LeapCent - 10

'  ** Jud McClendon correction to:
'  ** Epact = (11 * GoldenNo + 20 + LunarCorr - LeapCent) MOD 30
   Epact = (11 * GoldenNo + 30020 + LunarCorr - LeapCent) MOD 30

   IF ((Epact = 25) AND (GoldenNo > 11)) OR (Epact = 24) THEN
      Epact = Epact + 1
   END IF
   FullMoon = 44 - Epact
   IF FullMoon < 21 THEN
      FullMoon = FullMoon + 30
   END IF
   EasterDay = FullMoon + 7 - ((SundayCorr + FullMoon) MOD 7)
   IF EasterDay > 31 THEN
      EasterDay = EasterDay - 31
      EasterMonth = 4
   ELSE
      EasterMonth = 3
   END IF

   EasterMMDD = EasterMonth * 100 + EasterDay
   EasterKnuth = EasterMMDD
END FUNCTION


'
'  ** EasterKnuth2 Function **
'
'  Knuth's algorithm with Edward Moneo's Epact correction
'
FUNCTION EasterKnuth2(Year AS LONG) AS LONG
   DIM EasterMonth   AS LONG
   DIM EasterDay     AS LONG
   DIM EasterMMDD    AS LONG

   DIM GoldenNo      AS LONG
   DIM SundayCorr    AS LONG
   DIM Century       AS LONG
   DIM LeapCent      AS LONG
   DIM LunarCorr     AS LONG
   DIM Epact         AS LONG
   DIM FullMoon      AS LONG

   GoldenNo = (Year MOD 19) + 1
   Century = (Year \ 100) + 1
   LeapCent = ((3 * Century) \ 4) - 12
   LunarCorr = ((8 * Century + 5) \ 25) - 5
   SundayCorr = ((5 * Year) \ 4) - LeapCent - 10

'  ** Edward Moneo correction to:
'  ** Epact = (11 * GoldenNo + 20 + LunarCorr - LeapCent) MOD 30
   Epact = (11 * GoldenNo + 20 + LunarCorr - LeapCent)
   Epact = Epact - 30 * INT(Epact / 30)

   IF ((Epact = 25) AND (GoldenNo > 11)) OR (Epact = 24) THEN
      Epact = Epact + 1
   END IF
   FullMoon = 44 - Epact
   IF FullMoon < 21 THEN
      FullMoon = FullMoon + 30
   END IF
   EasterDay = FullMoon + 7 - ((SundayCorr + FullMoon) MOD 7)
   IF EasterDay > 31 THEN
      EasterDay = EasterDay - 31
      EasterMonth = 4
   ELSE
      EasterMonth = 3
   END IF

   EasterMMDD = EasterMonth * 100 + EasterDay
   EasterKnuth2 = EasterMMDD
END FUNCTION


'
'  ** EasterOudin Function **
'
'  Original Oudin algorithm from "Standard C Date/Time Library" page 169
'
FUNCTION EasterOudin(Year AS LONG) AS LONG
   DIM EasterMonth   AS LONG
   DIM EasterDay     AS LONG
   DIM EasterMMDD    AS LONG

   DIM C             AS LONG
   DIM N             AS LONG
   DIM Y             AS LONG
   DIM K             AS LONG
   DIM I             AS LONG
   DIM J             AS LONG
   DIM X             AS LONG

   Y = Year
   C = Y \ 100
   N = Y - 19 * (Y \ 19)
   K = (C - 17) \ 25
   I = C - C \ 4 - (C - K) \ 3 + 19 * N + 15
   I = I - 30 * (I \ 30)
   I = I - (I \ 28) * (1 - (I \ 28) * (29 \ (I + 1)) * ((21 - N) \ 11))
   J = Y + Y \ 4 + I + 2 - C + C \ 4
   J = J - 7 * (J \ 7)
   X = I - J
   EasterMonth = 3 + (X + 40) \ 44
   EasterDay = X + 28 - 31 * (EasterMonth \ 4)

   EasterMMDD = EasterMonth * 100 + EasterDay
   EasterOudin = EasterMMDD
END FUNCTION


'
'  ** EasterOudin2 Function **
'
'  Short Oudin algorithm by Claus Tonderings
'
FUNCTION EasterOudin2(Year AS LONG) AS LONG
   DIM EasterMonth   AS LONG
   DIM EasterDay     AS LONG
   DIM EasterMMDD    AS LONG

   DIM Century       AS LONG
   DIM G             AS LONG
   DIM I             AS LONG
   DIM J             AS LONG
   DIM K             AS LONG
   DIM L             AS LONG

   Century = Year \ 100
   G = Year MOD 19
   K = (Century - 17) \ 25
   I = (Century - Century \ 4 - (Century - K) \ 3 + 19 * G + 15) MOD 30
   I = I - (I \ 28) * (1 - (I \ 28) * (29 \ (I + 1)) * ((21 - G) \ 11))
   J = (Year + Year \ 4 + I + 2 - Century + Century \ 4) MOD 7
   L = I - J
   EasterMonth = 3 + (L + 40) \ 44
   EasterDay = L + 28 - 31 * (EasterMonth \ 4)

   EasterMMDD = EasterMonth * 100 + EasterDay
   EasterOudin2 = EasterMMDD
END FUNCTION


'
'  ** EasterButcher Function **
'
'  Butcher's Algorithm
'
FUNCTION EasterButcher(Year AS LONG) AS LONG
   DIM EasterMonth   AS LONG
   DIM EasterDay     AS LONG
   DIM EasterMMDD    AS LONG

   DIM A             AS LONG
   DIM B             AS LONG
   DIM C             AS LONG
   DIM D             AS LONG
   DIM E             AS LONG
   DIM F             AS LONG
   DIM G             AS LONG
   DIM H             AS LONG
   DIM I             AS LONG
   DIM K             AS LONG
   DIM L             AS LONG
   DIM M             AS LONG

   A = Year MOD 19
   B = Year \ 100
   C = Year MOD 100
   D = B \ 4
   E = B MOD 4
   F = (B + 8) \ 25
   G = (B - F + 1) \ 3
   H = (19 * A + B - D - G + 15) MOD 30
   I = C \ 4
   K = C MOD 4
   L = (32 + 2 * E + 2 * I - H - K) MOD 7
   M = (A + 11 * H + 22 * L) \ 451
   Eastermonth = (H + L - 7 * M + 114) \ 31
   Easterday = (H + L - 7 * M + 114) MOD 31 + 1

   EasterMMDD = EasterMonth * 100 + EasterDay
   EasterButcher = EasterMMDD
END FUNCTION
 




 1 Posts in Topic:
Easter calculation in the Gregorian Calendar
"Judson McClendon&qu  2007-10-19 13:46:49 

Post A Reply:
  Go here to Signup

AddThis Feed Button


About - Advertising - Contact - Frequently Asked Questions - Privacy Policy - Terms of Use - Signup

Contact
tan12V112 Thu Jul 24 15:23:11 CDT 2008.