Carterův algoritmus výpočtu Velikonoční neděle
Na internetu koluje i krátký algoritmus pro výpočet kalendářního data Velikonoční neděle, který však pracuje jen pro roky 1900 až 2099 gregoriánského kalendáře, což však v praxi mnohdy postačuje. Často je nazývaný Carterův algoritmus (dělení je vždy jen na celá čísla, tedy 23 / 5 = 4 a operátor '%' značí zbytek po dělení, například 23 % 5 = 3):
b = 225 - 11 * (rok % 19) |
d = (b - 21) % 30 + 21 |
je-li d větší jak 48, pak d = d - 1 |
e = (rok + rok / 4 + d + 1) % 7 |
q = d + 7 - e |
je-li q menší jak 32, pak je Velikonoční neděle q. března |
jinak je Velikonoční neděle (q - 31). dubna |
O autorovi se mi nepodařilo nic zjistit, jenom to, že algoritmus byl v roce 1996 uveřejněn v informačním letáku Royal Greenwich Observatory, jeho opis je nyní dostupný pouze v internetovém archivu: Information Leaflet No. 57: 'The Date of Easter'. Jen se domnívám, že algoritmus byl odvozen v historicky nedávné době, autor totiž použil techniky vhodné pro počítače. V dalším textu si algoritmus odvodíme pro juliánský kalendář, pak pro vybraná století gregoriánského kalendáře. Také nalezneme možná vylepšení a zjednodušení. A nakonec algoritmus upravíme pro všechny roky gregoriánského kalendáře. Zda-li tak učinil i autor, netuším.
Algoritmus pro juliánský kalendář
Při rozboru si nejprve situaci zjednodušíme a začneme sestavením podobného algoritmu pro juliánský kalendář. Nejprve si zhotovíme tabulku cyklických úplňků v juliánském kalendáři. V předposledním sloupci je vždy březnové datum úplňku, přičemž platí, že 1. duben = 32. březen a podobně. A v posledním najdeme rozdíl ve dnech mezi cyklickým úplňkem a 21. březnem, tedy církevním začátkem jara.
rok % 19 | cyklický úplněk | březen | dnů od 21.3. |
---|---|---|---|
0 | 5. dub | 36 | 15 |
1 | 25. bře | 25 | 4 |
2 | 13. dub | 44 | 23 |
3 | 2. dub | 33 | 12 |
4 | 22. bře | 22 | 1 |
5 | 10. dub | 41 | 20 |
6 | 30. bře | 30 | 9 |
7 | 18. dub | 49 | 28 |
8 | 7. dub | 38 | 17 |
9 | 27. bře | 27 | 6 |
10 | 15. dub | 46 | 25 |
11 | 4. dub | 35 | 14 |
12 | 24. bře | 24 | 3 |
13 | 12. dub | 43 | 22 |
14 | 1. dub | 32 | 11 |
15 | 21. bře | 21 | 0 |
16 | 9. dub | 40 | 19 |
17 | 29. bře | 29 | 8 |
18 | 17. dub | 48 | 27 |
Řada čísel v posledním sloupci začíná od 15, postupně se snižuje o 11, pokud je výsledek po snížení menší jak 0, přičte se 30 a tak stále dokola. Tuto řadu čísel dostaneme pomocí celkem jednoduchého výpočtu:
Bohužel v praxi však hned narazíme na problém a tím je často záporný dělenec při zjišťování zbytku po dělení 30. V závislosti na použitém programovacím jazyku počítač často vrátí nesprávný výsledek. Například programovací jazyk Python správně vrací:
(-23) % 5 2
Ale například PHP a Javascript vrací záporný výsledek, což není dobře. Tomu lze zabránit přičtením konstanty, jež je vhodným celočíselným násobkem dělitele, zbytek po dělení to neovlivní:
(-23) % 5, (-23 + 25) % 5 -3, 2
V tomto případě si také pomůžeme konstantou. Její minimální velikost najdeme takto: výraz 11×(rok%19) může nabýt maximální velikosti 198 (=11×18), odečteme 15 a najdeme nejbližší vyšší číslo, které je násobkem 30, tím je číslo 210. Toto číslo pak bez obav přičteme k výrazu aniž to ovlivní velikost zbytku po dělení.
Poznámka: stejnou řadu čísel vygenerujeme i za pomoci Gaussova vzorce, jenž je elegantnější, obejdeme se totiž bez přičítaných konstant:
Autora algoritmu zajímalo březnové datum úplňku (ve výše uvedené tabulce jde o předposlední sloupec), to dostaneme prostým přičtením čísla 21. Celý výpočet autor uvedl ve dvou řádcích, takže učiníme totéž i pro juliánský výpočet:
d = b % 30 + 21
V juliánském kalendáři existuje jen 19 možných hodnot d, viz předposlední sloupec tabulky výše. Nyní je zapotřebí zjistit den v týdnu pro cyklický úplněk, označíme jej e. Přitom platí, že pro neděli je e=0, pro pondělí je e=1 a tak dále až po sobotu, kdy e=6:
Nakonec zjistíme březnové datum Velikonoční neděle takto:
A to je vše, výsledek pak vypadá takto:
b = 225 - 11 * (rok % 19) |
d = b % 30 + 21 |
e = (rok + rok / 4) % 7 |
q = d + 7 - e |
je-li q menší jak 32, pak je Velikonoční neděle q. března |
jinak je Velikonoční neděle (q - 31). dubna |
Algoritmus pro gregoriánský kalendář
Takto jsme odvodili Carterův vzorec pro juliánský kalendář. V gregoriánském kalendáři nám situaci komplikuje posun cyklických novoluní o sedm dní a deset vypuštěných dnů při reformě, dále pak měnící se sluneční a měsíční oprava v různých stoletích. Další komplikovanost je zvláštní ošetření epakty 25. Nejprve odvodíme algoritmus pro roky 1583 až 1699 gregoriánského kalendáře, pro tyto roky je sluneční i měsíční oprava rovna 0. Řada cyklických úplňků nyní začíná o sedm dní později (10 dnů vypuštěných při reformě - 3 dny posun novoluní, více informací najdete na stránce Porovnání juliánských a gregoriánských cyklických výpočtů). Vzorec pro její vygenerování vypadá pak takto:
d = b % 30 + 21
Zde nastává potíž: výraz d, jenž zobrazuje březnové datum cyklického úplňku, může nabývat hodnot 0 až 50 (29+21). Pokud má hodnotu 50, znamená to, že cyklické novoluní by nastalo 19. dubna, což je nepřípustné (v juliánském kalendáři existuje jen 19 různých hodnot d, tato nejvyšší hodnota mezi ně nepatří). V gregoriánském kalendáři jsou tedy nejpozdější cyklické úplňky 'smrsknuty', viz tabulka:
d | epakta | cyklický úplněk |
---|---|---|
47 | 27 | 16. duben |
48 | 26 | 17. duben |
49 | 25/25 | 17/18. duben |
50 | 24 | 18. duben |
Při hodnotě d=50 je tak zapotřebí tuto hodnotu o den zmenšit, hodnota d=49 (tedy epakta 25) se v zmíněných letech nevyskytuje:
S ohledem na vypuštěných deset dnů musíme upravit i vzorec na určení dne týdne cyklického úplňku.
Zbytek je stejný:
b = 202 - 11 * (rok % 19) |
d = b % 30 + 21 |
je-li d rovno 50, pak d = 49 |
e = (rok + rok / 4 + d - 10) % 7 |
q = d + 7 - e |
je-li q menší jak 32, pak je Velikonoční neděle q. března |
jinak je Velikonoční neděle (q - 31). dubna |
Obdobně upravíme algoritmus pro roky 1900 až 2099, v těchto letech je sluneční oprava rovna 3 a měsíční oprava rovna 1. Konstanta ve výrazu b se zvětší o rozdíl sluneční a měsíční opravy, tedy o 2:
Výraz ve výpočtu dne týdne se zmenší o sluneční opravu, tedy o 3:
Opět také musíme zmenšit hodnotu d pro epaktu 24 a 25 (s dřívějším datem cyklického úplňku). Výsledek pak vypadá takto:
b = 204 - 11 * (rok % 19) |
d = b % 30 + 21 |
je-li d větší jak 48, pak d = d - 1 |
e = (rok + rok / 4 + d - 13) % 7 |
q = d + 7 - e |
je-li q menší jak 32, pak je Velikonoční neděle q. března |
jinak je Velikonoční neděle (q - 31). dubna |
Pozorný čtenář nyní s údivem zjistí, že jsme odvodili trochu jiný algoritmus než je ten v úvodu stránky. Rozdíl je v tom, že autor algoritmu při výpočtu d odečítá od b číslo 21, o tolik tedy musí být zase zvětšena konstanta ve výpočtu b:
b = 225 - 11 * (rok % 19) |
d = (b - 21) % 30 + 21 |
Proč to autor udělal mi není známo, je to totiž naprosto zbytečné! Další drobný rozdíl je v odečítané konstantě při výpočtu e. Zde se odečítá třináctidenní rozdíl mezi kalendáři, autor přičítá 1. K -13 totiž připočetl 14, což je násobek 7 a jak už víme při počítání zbytku po dělení 7 toto vůbec nevadí. V tomto případě je to sice zbytečné, výraz v závorce určitě nebude záporný, ale lépe to vypadá:
e = (rok + rok / 4 + d + 1) % 7 |
Nyní už zbývá odvodit Carterův vzorec pro všechny roky gregoriánského kalendáře, několik řádků přibude, je to výpočet sluneční a měsíční opravy. Současně je zapotřebí ošetřit i zvláštní chování epakty 25.
a = rok % 19 |
k = rok / 100 |
s = k - k / 4 - 12 |
m = 8 * (k - 14) / 25 |
b = 202 + s - m - 11 * a |
d = b % 30 + 21 |
je-li d rovno 49 a současně 'a' větší jak 10, pak d = d - 1 |
je-li d rovno 50, pak d = d - 1 |
e = (rok + rok / 4 + d - 10 - s) % 7 |
q = d + 7 - e |
je-li q menší jak 32, pak je Velikonoční neděle q. března |
jinak je Velikonoční neděle (q - 31). dubna |
Pokud využijeme zmiňovaného Gaussova vylepšení výpočtu cyklického úplňku, můžeme výpočet d zkrátit do jediného řádku, bez nutnosti počítat b:
d = (19 * a + 22 + s - m) % 30 + 21 |
Podstata algoritmu je stejná jako u Gaussova algoritmu, ale i jiných. Vypočteme rovnou pozici cyklického úplňku, bez nutnosti výpočtu epakty. Následující neděle je pak hledaná Velikonoční neděle. V gregoriánském kalendáři jsou pak navíc ještě nutné úpravy v závislosti na století.