Why Yet Another Easter Algorithm?

I have posted programs implementing an Easter algorithm that I have developed. But one question you may have is why you should use my algorithm as opposed to other more common algorithms. The first few reasons are given in that page: it gives correct values for proleptic Gregorian Easters all the way from 0 forward, and it never gives a negative number even as an intermediate result so one doesn't have to worry about the fact that integer division and modulus operators are not consistently defined for negative inputs across languages. And as a side benefit, the value of the (Ecclesiastical) Paschal Full Moon is calculated as an intermediate result which allows working with that -- eg, comparing it to the astronomical Full Moon. But there are other issues with many commonly given Easter algorithms.

There are the wrong Easter algorithms. One simple one is:

def Easter(year): a=year%19 b=year%4 c=year%7 d=(19*a+24)%30 e=(2*b+4*c+6*d+5)%7 easter=d+e+22 if easter>31: return (4,easter-31) else: return (3,easter)

The validity range for this algorithm is often given as 1900 to 2099 (inclusive), however this is incorrect; this algorithm fails to given the correct date for Easter is 1954, 1981, 2049, and 2076. Some sources handle this problem by defining the range of validity as being 1982 to 2048 (inclusive). Others write the algorithm as:

def Easter(year): a=year%19 b=year%4 c=year%7 d=(19*a+24)%30 e=(2*b+4*c+6*d+5)%7 easter=d+e+22 if year in (1954,1981,2049,2076): easter-=7 if easter>31: return (4,easter-31) else: return (3,easter)

Note the hack of using an explicit test for the 4 years in question.

Some have the minor flaw of feeding negative numbers to the integer division or modulus operators for some years prior to 1583. (I do not give an example of one of those.) This can be justified by the fact that Gregorian Easter was observed nowhere before 1583. However as explained in a footnote on the year 0 in the other page, it is more convenient for analyses of patterns of Easter dates should the algorithm "correctly" continue the pattern of the 5700000 year repeat cycle all the way down to an input of 0(inclusive). This costs nothing in my algorithm.

There are others that are limited to years less than 4200, though sometimes this is not even stated as a limitation (probably because those writing about such defective algorithms do not even know that there is a problem). (I also do not give an example of one of these either.)

Finally, some are too complex in my opinion because they lead to the temptation to simply things by using an algorithm with limited range. The algorithm popularized by Jean Meeus falls in to this category. The Meeus algorithm is:

def Easter(year): a=year%19 b=year//100 c=year%100 d=b//4 e=b%4 f=(b+8)//25 g=(b-f+1)//3 h=(19*a+b-d-g+15)%30 i=c//4 k=c%4 l=(2*e+2*i-h-k+32)%7 m=(a+11*h+22*l)//451 z=h+l-7*m+114 return (z//31,z%31+1)

While this does have the advantage of giving correct values for proleptic Gregorian Easters all the way from 0 forward and never feeding a negative number to the integer division and modulus operators, it uses significantly more operations than mine and the connection to more standard descriptions for computing the date of Easter is as clear as mud.

My final correct Easter algorithm is a result of code golfing for the fewest number of operations and variables used rather than fewest characters. This code has the same problem of having the connection to more standard descriptions for computing the date of Easter being obscure, but gives correct values for proleptic Gregorian Easters all the way from 0 forward and avoids negative numbers. I do not recommend this algorithm; the savings of one comparison operation in the typical case and one addition and a few intermediate variables is not in my opinion worth the obscuration. I recommend the algorithm in my other page. however, I do present this algorithm as an exercise in code golf. I believe that this final algorithm is the best one can do if one insists on using the fewest operations possible with using tables and giving correct values for Gregorian Easter for all years after 1582; if you know of a way to reduce the number of operations further you can email me.

def Easter(y): a=y%19 b=y//100 c=b-b//4 b=(19*a+15+c-(8*b+13)//25)%30 if b>=28 and (b==29 or a>10): b-=1 a=b+28-(b+2+y+y//4-c)%7 if a>31: return (4,a-31) else: return (3,a)