ESTRALGS.TXT - More algorithms for Easter Sunday as Day-of-March (c) www.merlyn.demon.co.uk >= 2011-04-27 estrdate.htm estralgs.txt My copyright applies to this document, but not to the algorithms which it contains. This page contains algorithms in Javascript, not necessarily present elsewhere on my site, for the date of Easter Sunday as a Day-of-March, in a layout suited to pasting a function body into the text area of the form in the section "Test a Provided Function" of my Web page , in order that their bodies may be used in that section and in the following section, "General Testing and Timing". For that, the argument must be 'YR', and the return must be Day-of-March. This page also contains code for testing with CScript in Windows WSH at a Command Prompt, exceeding the full cycle of 5700000 years. Note to C users : for a>=0, b>0 JavaScript ~~(a/b) and (a/b)|0 are Math.floor(a/b) is C a\b . ----------------------------------------------------------------------- Samuel Butcher, Bishop of Meath function ButcherEaster1(YR) { // After http://www.smart.net/~mmontes/butcher.html var a, b, c, d, e, f, g, h, i, k, l, m, p, EstrMnth, EstrDate a = YR % 19 b = (YR/100)|0 c = YR%100 d = (b/4)|0 e = b%4 f = ((b+8)/25)|0 g = ((b-f+1)/3)|0 h = (19*a+b-d-g+15)%30 i = (c/4)|0 k = c%4 l = (32+2*e+2*i-h-k)%7 m = ((a+11*h+22*l)/451)|0 EstrMnth = ((h+l-7*m+114)/31)|0 // 3=March, 4=April p = (h+l-7*m+114)%31 EstrDate = p+1 // date in Easter Month return EstrDate + 31*(EstrMnth-3) // added by JRS to return DoM } function ButcherEaster2(YR) { // After http://www.smart.net/~mmontes/butcher.html ; now just DoM var a, b, c, d, e, f, g, h, i, k, l, m a = YR % 19 b = (YR/100)|0 c = YR%100 d = (b/4)|0 e = b%4 f = ((b+8)/25)|0 g = ((b-f+1)/3)|0 h = (19*a+b-d-g+15)%30 i = (c/4)|0 k = c%4 l = (32+2*e+2*i-h-k)%7 m = ((a+11*h+22*l)/451)|0 return h + l - 7*m + 22 // modified by JRS 20080430 to return DoM } ----------------------------------------------------------------------- Simon Kershaw, SoAJ ADAPTED by JRS from http://archive.ely.anglican.org/etc/easter2.c as at 2008-04-22. See http://www.oremus.org/liturgy/etc/ktf/app/easter.html TESTED IN ESTRDATE.HTM, April 2008 Note : easter2.c contains a Julian part. function SimonKershaw(YR) { var golden, solar, lunar, pfm, dom, tmp, easter; // Golden Number golden = (YR % 19) + 1; // "Dominical Number" - finding a Sunday dom = ( YR + ((YR/4)|0)-((YR/100)|0)+((YR/400)|0) ) % 7; if (dom < 0) dom += 7; // Solar and Lunar corrections solar = (((YR-1600)/100)|0) - (((YR-1600)/400)|0) ; lunar = ((( (((YR-1400) / 100)|0) * 8) / 25)|0); // Uncorrected date of the Paschal full moon pfm = (3 - (11*golden) + solar - lunar) % 30; if (pfm < 0) pfm += 30; // Corrected date of the Paschal full moon - days after March 21 if ((pfm == 29) || (pfm == 28 && golden > 11)) pfm--; tmp = (4-pfm-dom) % 7; if (tmp < 0) tmp += 7; // Easter as the number of days after 21st March easter = pfm + tmp + 1; return easter + 21 // Added by JRS in liew of month/day code } OK all years when using Math.floor; OK after 1500 with |0 . With |0, rather fast. ----------------------------------------------------------------------- Anon, put in Wikipedia computus Discussion by A1jrj, 2008-05-01; to JavaScript by JRS. function MaybeGauss1(YR) { var a, b, c, d, e, g, h, n, i, k, l a = YR%19 c = YR%100 ; b = (YR-c)/100 e = b%4 ; d = (b-e)/4 g = ((8*b+13)/25)|0 h = (19*a+b-d-g+15)%30 m = ((a+11*h)/319)|0 k = c%4 ; i = (c-k)/4 l = (2*e+2*i-k-h+m+32)%7 month = ((h-m+l+90)/25)|0 day = (h-m+l+month+19)%32 return (month-3)*31 + day // Added by JRS } function MaybeGauss2(YR) { var a, b, c, d, e, g, h, n, i, k, l a = YR%19 c = YR%100 ; b = (YR-c)/100 e = b%4 ; d = (b-e)/4 g = ((8*b+13)/25)|0 h = (19*a+b-d-g+15)%30 m = ((a+11*h)/319)|0 k = c%4 ; i = (c-k)/4 l = (2*e+2*i-k-h+m+32)%7 return h-m+l + 22 // Added by JRS, for DoM } Oliver Pretzel, Imperial College, London, reported, 2010-11-11 : The two algorithms called MaybeGauss1 and MaybeGauss2 in estralgs.txt are from the chapter "10 Divisions lead to Easter" of the book "Puzzles and Paradoxes" by T H O'Beirne (London 1965). This is a collection of articles written by O'Beirne in the 50s and 60s. From the text of the book it would appear that he is responsible for the algorithms. Therefore : ----------------------------------------------------------------------- JRS : search the Web for "Divisions lead to Easter", finding New Scientist, No. 228, 30 March 1961 (at Google Books). Table 1 yields : function THOBeirne(YR) { // notes compare with MaybeGauss2 var a, b, c, d, e, g, h, i, k, l, m, n, p // x = YR a = YR%19 c = YR%100 ; b = (YR-c)/100 e = b%4 ; d = (b-e)/4 g = ((8*b+13)/25)|0 h = (19*a+b-d-g+15)%30 k = c%4 ; i = (c-k)/4 l = (2*e+2*i-h-k+32)%7 m = ((a+11*h+19*l)/433)|0 n = (h + l - 7*m + 90)/25|0 p = (h + l - 7*m + 33*n + 19)%32 return (n-3)*31 + p // Added by JRS, for DoM } ----------------------------------------------------------------------- Lilius / Clavius / Knuth / McClendon translated from 11-25-2007 by JRS, adjusted and tested, fast : function McClendon(YR) { var g, c, x, z, d, e, n g = YR % 19 + 1 // Golden c = ((YR/100)|0) + 1 // Century x = ((3*c/4)|0) - 12 // Solar z = (((8*c+5)/25)|0) - 5 // Lunar d = ((5*YR/4)|0) - x - 10 // Letter ? e = (11*g + 20 + z - x) % 30 // Epact if (e<0) e += 30 // Fix 9006 problem if ( ( (e==25) && (g>11) ) || (e==24) ) e++ n = 44 - e if (n<21) n += 30 // PFM return n + 7 - ((d+n)%7) // Following Sunday } MW : "Knuth, TAoCP, vol 1 (Fundamental Algorithms), 3rd ed, 1.3.2 ex 14 is the Easter Sunday problem". ----------------------------------------------------------------------- Lilius / Clavius, translated from Henk Reints' page , 2009-02-20 function HenkClavius(YR) { var A, B, C, D, E, F, G, year=YR A = year % 19 + 1 B = (year/100|0) + 1 C = (3*B/4|0) - 12 D = ((8*B+5)/25|0) - 5 E = (year*5/4|0) - 10 - C F = ( (11*A + 20 + D - C) % 30 + 30) % 30 /* the double MOD stops F going below zero for large years */ if (F == 24 || (F == 25 && A > 11) ) F = F + 1 G = 44 - F if (G < 21) G = G + 30 return G + 7 - (E + G) % 7 } ----------------------------------------------------------------------- // After http://www.ptb.de/de/org/4/44/441/oste.htm ~ 2007-08-30 // And http://www.ptb.de/de/org/4/44/441/oste-e.htm // Dr. Heiner Lichtenberg, Bonn // Test in estrdate.htm#VR ff. // Direct translation function Lichtenberg(YR) { var X = YR, K, M, S, A, D, R, OG, SZ, OE function INT(X) { return X|0 } function MOD(X, Y) { return X%Y } K = INT (X/100) M = 15 + INT ((3*K+3)/4) - INT ((8*K+13)/25) S = 2 - INT ((3*K+3)/4) A = MOD (X, 19) D = MOD (19*A+M, 30) R = INT (D/29) + (INT (D/28) - INT (D/ 29)) * INT (A/11) OG = 21 + D - R SZ = 7 - MOD (X+INT (X/4)+S, 7) OE = 7 - MOD (OG-SZ, 7) return OG + OE } HL wrote that one can improve the R line as R = int((D + A/11)/29). Confirmed. --------------------- // Optimising INT with integer-OR and MOD with % function Lichtenberg(YR) { var K, M, S, A, D, R, OG, SZ, OE K = (YR/100) | 0 M = 15 + ( ((3*K+3)/4 ) | 0 ) - ( ((8*K+13)/25) | 0 ) S = 2 - ( ((3*K+3)/4) | 0 ) A = YR % 19 D = (19*A+M) % 30 R = ((D/29)|0) + ( ((D/28)|0) - ((D/29)|0) ) * ((A/11)|0) // R = ((D + A/11)/29)|0 // message from HL OG = 21 + D - R SZ = 7 - (YR + ((YR/4)|0) + S) % 7 OE = 7 - (OG-SZ) % 7 return OG + OE } ----------------------------------------------------------------------- A speed increase for jrsEaster, after I'd read Knuth's. Now in estr-bcp.htm. function EasterJRS(YR) { // Faster jrsEaster, unsigned 32-bit year var gn, xx, cy, qq, DM gn = YR % 19 // gn ~ GoldenNumber xx = (YR/100)|0 cy = (qq=((3*(xx+1)/4)|0)) - (((13+xx*8)/25)|0) // cy ~ BCPcypher //xx = ( 6 + ((5*YR/4)|0) - xx + ((YR/400)|0) ) % 7 xx = ( 6 + ((5*YR/4)|0) - qq ) % 7 // cf. Knuth DM = 21 + (gn*19 + cy + 15)%30 ; DM -= ((gn>10) + DM > 49) // PFM return DM + 1 + (66-xx-DM)%7 /* Day-of-March */ } ----------------------------------------------------------------------- From the Irish, in IE-PB-ES.HTM, 12, from De Morgan, "A Budget of Paradoxes". Works for years 1600 to 3164 inclusive; adjacent years fail. refers. function IrishEaster(YR) { var t, CC = YR/100|0 var I, II, III, IV, V, VI, VII, VIII, IX, X, XI, XII, XIII, XIV, XV I = YR + 1 II = YR / 4 | 0 III = CC >= 16 ? CC-16 : CC IV = III / 4 | 0 V = I + II + IV - III VI = V % 7 VII = 7 - VI // Sun Num 1-7 = A=G VIII = (t=I%19) > 0 ? t : 19 // GN IX = (CC - 17) / 25 | 0 // ??? CC < 17 ??? X = (CC - IX - 15) / 3 | 0 XI = ( VIII + 10*(VIII-1) ) % 30 XII = (XI + X + IV - III) % 30 if (XII==25 && VIII>11) XII = 26 if (XII==24) XII = 25 if (XII==0) XII = 30 // XII now is Epact if (XII<=23) { XIII = 45 - XII XIV = (t=(27-XII)%7) > 0 ? t : 7 } if (XII> 23) { XIII = 75 - XII XIV = (t=(57-XII)%7) > 0 ? t : 7 } XV = XIII + VII ; if (XIV>VII) XV += 7 ; XV -= XIV // DoM return XV // OK 1600-3164 } ----------------------------------------------------------------------- GAUSS Gregorian Easter from http://en.wikipedia.org/wiki/Computus - works OK See http://de.wikipedia.org/wiki/Gau%C3%9Fsche_Osterformel which is similar, presumably equivalent, but not identical. function GaussEaster(YR) { var a, b, c, k, p, q, M, N, d, e, Ans, year = YR // Expression // AD 1777 a = year % 19 // a = 10 b = year % 4 // b = 1 c = year % 7 // c = 6 k = Math.floor(year/100) // k = 17 p = Math.floor((13 + 8*k)/25) // p = 5 q = Math.floor(k/4) // q = 4 M = (15 - p + k - q) % 30 // M = 23 N = (4 + k - q) % 7 // N = 3 d = (19*a + M) % 30 // d = 3 e = (2*b + 4*c + 6*d + N) % 7 // e = 5 // Easter is 22 + d + e March or d + e - 9 April // 30 March // if d = 29 and e = 6, replace 26 Apr by 19 // if d = 28, e = 6, (11M + 11) mod 30 < 19, replace 25 Apr by 18 // JRS's equivalent :- Ans = 22 + d + e if (e != 6) return Ans if (d == 29 || (d == 28 && (11*M + 11) % 30 < 19 ) ) Ans -= 7 return Ans } ----------------------------------------------------------------------- NOTE : this ops count treats /| as one, and ignores = I think. Al Petrofsky, San Mateo County, California, U.S.A., E-mail 2009-04-19 Tested, OK, very fast, 22 basic arithmetic ops : faster than jrsEaster. function Easter22ops(YR) { var cents, qcents, foo, SN, t3row, PFMeq; cents = (YR / 100)|0; qcents = (cents / 4)|0; foo = (cents + 1258) * 2267; SN = YR % 19; t3row = (19 * SN + ((foo / 25)|0) - qcents) % 30; PFMeq = t3row - (((t3row * 11 + SN) / 319)|0); return 28 + PFMeq - (PFMeq + YR + ((YR / 4)|0) + qcents + foo) % 7; } To get Month & Date replace return line with EasterMA93 = 120 + PFMeq - (PFMeq + YR + ((YR / 4)|0) + qcents + foo) % 7; Easter_Month = (EasterMA93 / 31)|0; Easter_Day = EasterMA93 % 31 + 1; //JRS : and arrange to return those ----- Al Petrofsky, San Mateo County, California, U.S.A., E-mail 2009-04-20 Same algorithm, more understandable, good for 0 <= YR < 2,368,074,100 function Easter22ops(YR) { var cents, quadcents, GN1, foo, Epact53, PFMeq, PFM7Easter, EasterMarchDay; cents = (YR / 100)|0; // centuries quadcents = (YR / 400)|0; // quadcenturies GN1 = YR % 19; // Golden Number minus one // foo is a multi-purpose value with constants chosen so that: // modulo 30: foo / 25 == (cents + 8) * 17 / 25 + 10 // and modulo 7: foo == 2 - cents foo = (cents + 1258) * 2267; // Epact53 is (53 - Epact) % 30. // Values correspond to rows of UK Calendar Act table III // (counting row 28, split between April 17 and 18, as one row). Epact53 = (19 * GN1 + ((foo / 25)|0) - quadcents) % 30; // Paschal Full Moon minus March 21st. PFMeq = Epact53 - (((Epact53 * 11 + GN1) / 319)|0); // PFM7Easter is PFM + 7 - Easter, // or the number of days that come after this Easter but on or // before the last possible Easter date for this PFM date. PFM7Easter = (PFMeq + YR + ((YR / 4)|0) + foo + quadcents) % 7; // Easter - March 0th EasterMarchDay = 28 + PFMeq - PFM7Easter; return EasterMarchDay; } To get month & day in 25 operations, replace EasterMarchDay line with: EasterM92 = 120 + PFMeq - PFM7Easter; // 92 + Easter - March 0th EasterMonth = (EasterM92 / 31)|0; // 3 for March, 4 for April EasterDay = EasterM92 % 31 + 1; // Day within EasterMonth ----- Al Petrofsky, San Mateo County, California, U.S.A., E-mail 2009-04-30 21 basic arithmetic ops function Easter21ops(YR) { var a = (YR / 100 |0) * 2267 - (YR / 400 |0) * 6775 + 3411; var b = (YR % 19 * 6060 + (a / 25 |0) * 319 - 1) % 9570 / 330 |0; return 28 + b - ((YR * 5 / 4 |0) + a + b) % 7; // To get Month & Day in 24 total arithmetic operations, use: // c = 120 + b - ((YR * 5 / 4 |0) + a + b) % 7; // Month = c / 31 |0; // Day = c % 31 + 1; // The coefficients in the formula for A were chosen so that both of // these equations would hold: // // a / 25 % 30 == ((y / 100 * 17 + 11) / 25 - y / 400 + 16) % 30 // a % 7 == (y / 400 + y / 100 * 6 + 2) % 7 // As a result, the formulae for B and the return value are // equivalent to: // // b = ( 29 * 11 * (15 + y % 19 * 19 // + y / 100 - y / 400 // - ( (y / 100 + 25 - 14) * 8 / 25 // - ( 25 - 14) * 8 / 25) // + 1) // - 1 - y % 19) // % (30 * 29 * 11) / (30 * 11) // return 28 + b - (2 + b + y + y / 4 - y / 100 + y / 400) % 7 // B represents the date of the Paschal Full Moon, ranging from 0 // for March 21st to 28 for April 18th. // // Here are some pertinent facts about the constants in these // formulae: // // 400 is the number of years in the cycle of solar corrections. // 100 is the number of years between solar or lunar corrections. // 30 is the number of different epacts (not distinguishing xxv and 25). // 29 is the number of different Paschal Full Moon dates. // 28 is the day of March one week after the equinox. // 25 is the number of centuries in the cycle of lunar corrections. // 19 is the number of years in the Metonic cycle. // 19 is also the ordinary decrement from one year's epact to the next. // 15 is the number of days after the equinox that the Paschal // Full Moon falls, in the year zero. // 14 is one hundredth of the year at the start of the first span of // four centuries between lunar corrections. // 11 is the number of golden numbers for which epact xxv/25 maps to // a Paschal Full Moon date of April 18th rather than April 17th. // 8 is the number of lunar corrections per 25 centuries. // 7 is the number of days in the week. // 4 is the number of years in the uncorrected leap year cycle. // 2 is the number of days that are after the first Sunday after the // equinox, but on or before March 28, in the year zero. // Implementation limits: // In C and other languages and systems with ordinary fixed-width // 32-bit unsigned integer arithmetic, the function fails due to // overflow at year 58,714,311, and with 64-bit integers, it fails // at year 252,188,329,394,345,111. In either case, if a "y = y % // 5700000" line is added at the start of the function, then correct // results will be returned for all possible inputs. // In ECMAscript/javascript: the language has no integer division // operator, and non-integer division results must somehow be // rounded down. If division results are truncated by using a // bitwise logical operation (e.g. "|0") to cause an internal // floating-point-to-integer conversion, then the first year for // which the function fails is 1,717,986,919, which is when (y * 5 / // 4) first exceeds the 31-bit range for unsigned logical integer // values. If division results are truncated using the Math.floor // function, then first failure comes at year 123,138,832,709,500, // shortly after the sum in the B formula first exceeds the 53-bit // positive range over which IEEE 64-bit floating point values have // integer precision. In either case, if a "y = y % 5700000" line // is added at the start of the function, then the correct result // will be returned for any input that is a non-negative integer. } ----- Al Petrofsky, San Mateo County, California, U.S.A., E-mail 2009-05-02 Here's an implementation for finding the Emended Gregorian Easter: // JRS: Seemingly a non-accepted part of Clavius. function EmendedGregorianEaster(YR) { var a = (YR / 100 |0) * 2967 - (YR / 400 |0) * 8875 + 7961; var b = ( (YR % 19 * 6060 + ((a / 25 |0) % 59 % 30 + 23) * 319 - 1) % 9570 / 330 |0); return b + 28 - ((YR * 5 / 4 |0) + a + b) % 7; } ----- Al Petrofsky, San Mateo County, California, U.S.A., E-mail 2009-05-22 function Easter20ops(YR) { var a = ~~(YR / 100) * 1483 - ~~(YR / 400) * 2225 + 2613; var b = ~~((YR % 19 * 3510 + ~~(a / 25) * 319) / 330) % 29; return 56 - b - (~~(YR * 5 / 4) + a - b) % 7; // To get Month & Day in 23 total arithmetic operations, use: // c = 148 - b - (~~(YR * 5 / 4) + a - b) % 7; // Month = ~~(c / 31); // Day = c % 31 + 1; } ----- Al Petrofsky, San Mateo County, California, U.S.A., E-mail 2009-05-19 included the bodies of, among others, function FastGregorianEaster(YR) { // SELECT ONE BODY // Limited-domain Gregorian Easter algorithms for various intervals // from one change of Clavian index letter (British Calendar Act // cypher) to the next: // years 1700-1899 (12 ops) var a = (YR % 19 * 11 + 5) % 30; return 56 - a - ((YR * 5 / 4 |0) - (YR / 150 |0) - a) % 7; // years 1900-2199 (13 ops) var a = ((YR % 19 * 319 + 146) / 30 |0) % 29; return 56 - a - ((YR * 5 / 4 |0) - (YR / 300 |0) - a) % 7; // years 2200-2299 (12 ops) var a = ((YR % 19 + 14) * 319 / 30 |0) % 29; return 56 - a - ((YR * 5 / 4 |0) - 1 - a) % 7; // However, there are some change-to-change intervals in which you // can get by with only 9 ops: // years 303600-303699 (9 ops) var a = YR % 19 * 19 % 30; return 28 + a - ((YR * 5 / 4 |0) + a) % 7; } function FastJulianEaster(YR) { // Nicean Easter, as a day of March, for any YR >= 0 var a = (YR % 19 * 19 + 15) % 30; return 28 + a - ((YR * 5 / 4 |0) + a) % 7; } function ShortGregorianEaster1(YR) { var a=YR/100|0,b=a>>2,c=(YR%19*351-~(b+a*29.32+13.54)*31.9)/33%29|0;return 56-c-~(a-b+c-24-YR/.8)%7 } Adding a touch of whitespace for readability, that's: function ShortGregorianEaster2(YR) { var a=YR/100|0, b=a>>2, c=(YR%19*351-~(b+a*29.32+13.54)*31.9)/33%29|0; return 56-c-~(a-b+c-24-YR/.8)%7 } function NoVarGregorianEaster(YR) { return ~~((170 - ~~((YR % 19 * 3510 + (~~((~~(YR / 100) * 733 + 363) / 25) + ~~(YR / 400)) * 319) / 330) % 29 + (YR + ~~(YR / 4) - ~~(YR / 100) + ~~(YR / 400)) * 57) / 7) * 7 % 57; } ----------------------------------------------------------------------- Ian Taylor, Cambs UK, E-mail 2010-12-10, wrote : " ... a JavaScript snippet I've come up with that computes Gregorian Easter for all years 0 to 65535 inclusive using only 16-bit unsigned integers with no branching, conditions, table lookups or even divisions. ... " (JRS: Actually gives correct answers for years 0 to 158099. See and thereabouts.) function IanTaylorEasterJscr(YR) { var a, b, c, d, e, f, g, h; a = YR >>> 1; b = YR >>> 2; c = YR >>> 4; d = b + c; e = (a + d + (d >>> 4) + (d >>> 5) + (d >>> 10)) >>> 4; f = YR - e * 19; g = f - ((f + 13) >>> 5) * 19; d = (b >>> 1) + (b >>> 3); e = (d + (d >>> 6) + (d >>> 7)) >>> 4; f = b - e * 25 + 39; d = e + (f >>> 5); h = (d * 3) >>> 2; d = (d * 8) + 5; e = (d >>> 1) + (d >>> 3); e = (e + (e >>> 6) + (e >>> 7)) >>> 4; f = d - (e * 25) + 7; d = (g * 19) + h - e - (f >>> 5) + 15; e = ((d >>> 1) + (d >>> 5)) >>> 4; f = d - (e * 30); d = f - ((f + 2) >>> 5) * 30; g = d + ((29578 - g - (d * 32)) >>> 10); f = b - h + g + 2; d = a + c + (f >>> 1) + (f >>> 4); e = (d + (d >>> 6) + (d >>> 12)) >>> 2; f += YR - (e * 7); e = g - f + ((f * 2341) >>> 14) * 7; return e; } /***** // (Mostly) equivalent to the following 16-bit C function void easter_u16(u16 year, u16* month, u16* day) { u16 a = year % 19; u16 b = year >> 2; u16 c = (b / 25) + 1; u16 d = (c * 3) >> 2; u16 e = ((a * 19) - ((c * 8 + 5) / 25) + d + 15) % 30; e += (29578 - a - e * 32) >> 10; e -= ((year % 7) + b - d + e + 2) % 7; d = e >> 5; *day = e - d * 31; *month = d + 3; } *****/ That in JavaScript : Correct for at least years 0 to 12000000 function IanTaylorEasterJscr(YR) { var a, b, c, d, e a = YR % 19 b = YR >> 2 c = ((b / 25)|0) + 1 d = (c * 3) >> 2 e = ((a * 19) - (((c * 8 + 5) / 25)|0) + d + 15) % 30 e += (29578 - a - e * 32) >> 10 e -= ((YR % 7) + b - d + e + 2) % 7 return e // the following not tested : // d = e >> 5 // day = e - d * 31 // month = d + 3 /* Opera : remove previous 3 // for crash test */ } ----------------------------------------------------------------------- JRS: function BriefFastEaster(YR) { // 2000 to 2030 only return [54,46,31,51,42,27,47,39,23,43,35,55,39,31,51, 36,27,47,32,52,43,35,48,40,31,51,36,28,47,32,52][YR-2000] } ----- function BriefFasterEaster(YR) { // 2000 to 2030 only, untested return BriefFasterEaster.DoM[YR-2000] } BriefFasterEaster.DoM = [54,46,31,51,42,27,47,39,23,43,35,55,39,31,51, 36,27,47,32,52,43,35,48,40,31,51,36,28,47,32,52] ----- function CachedEaster(YR) { if (!window.Global) window.Global = [] return Global[YR] || (Global[YR] = ZEG1886(YR)) } In IE and FF, not as good as hoped. ----------------------------------------------------------------------- After Wikipedia "Computus" Discussion, copied 20110425, corrected -27 function TonyHutchins(YR) { var a, b, c, d, e, f, g, h, j, k a = YR % 19 b = YR / 100 | 0 c = YR / 4 | 0 d = (3*b+3) / 4 | 0 e = (8*b+13) / 25 | 0 f = (19*a+d-e+15) % 30 g = (a+11*f) / 319 | 0 h = (f-g+YR+c+2 -d ) % 7 // -d term added by JRS to make it work return f-g-h + 28 // By JRS, to give Day-of-March directly //// var T = f-g-h+120 ; j = T / 31 | 0 ; k = T % 31 //// // Easter Sunday in Gregorian year YR falls on day k+1 of month j //// return (j-3)*31 + k + 1 // By JRS, to give Day-of-March } ----------------------------------------------------------------------- 8<===================================================================== // WSH CScript or WScript Javascript for non-stop full-range comparison // and for timing. Copy this section to estrtest.js, adjust, run. // CScript //nologo //T:nn estrtest.js // nn is timeout in seconds, default none function Verify() { var Y, A, B, St for (Y=0 ; Y<=6e6 ; Y++) { A = jrsEaster(Y) B = Func(Y) if (A!=B) return "Bad " + Y + " " + A + " " + B if (Y%2e4 == 0) { St = " "+Y // show progress WScript.StdOut.Write(St.substr(St.length-8)+"\x0D") } // EjH } return "\n OK" } function Timing() { var K, D0, D1, D2, D3, Q K = 200000 // adjust D0 = new Date() Q = K ; while (Q--) { } D1 = new Date() Q = K ; while (Q--) { jrsEaster(K) } D2 = new Date() Q = K ; while (Q--) { Func(K) } D3 = new Date() WScript.echo("Times := ", [D1-D0, D2-D1, D3-D2]) // times } // known good, but not my fastest :- function jrsEaster(YR) { // Fast JRSEaster, unsigned 32-bit year var gn, xx, cy, DM gn = YR % 19 // gn ~ GoldenNumber xx = (YR/100)|0 cy = ((3*(xx+1)/4)|0) - (((13+xx*8)/25)|0) // cy ~ BCPcypher xx = ( 6 + YR + ((YR/4)|0) - xx + ((YR/400)|0) ) % 7 DM = 21 + (gn*19 + cy + 15)%30 ; DM -= ((gn>10) + DM > 49) // PFM return DM + 1 + (66-xx-DM)%7 /* Day-of-March */ } function Func(YR) { /* Replace body with test YR to DoM function */ } // Normally, uncomment one :- // WScript.echo(Verify()) WScript.echo(Timing()) // END. 8<===================================================================== END