Menu ≡
kalendar.beda.cz

Carterův algoritmus výpočtu Velikonoční neděle

English version

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):

Původní Carterův algoritmus pro roky 1900 až 2099
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 % 19cyklický
úplněk
březendnů od
21.3.
05. dub3615
125. bře254
213. dub4423
32. dub3312
422. bře221
510. dub4120
630. bře309
718. dub4928
87. dub3817
927. bře276
1015. dub4625
114. dub3514
1224. bře243
1312. dub4322
141. dub3211
1521. bře210
169. dub4019
1729. bře298
1817. dub4827

Ř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:

(15 - 11 × (rok % 19)) % 30

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í.

(225 - 11 × (rok % 19)) % 30

Poznámka: stejnou řadu čísel vygenerujeme i za pomoci Gaussova vzorce, jenž je elegantnější, obejdeme se totiž bez přičítaných konstant:

(15 + 19 × (rok % 19)) % 30

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:

b = 225 - 11 × (rok % 19)
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:

e = (rok + rok / 4 + d) % 7

Nakonec zjistíme březnové datum Velikonoční neděle takto:

q = d + 7 - e

A to je vše, výsledek pak vypadá takto:

Carterův algoritmus pro juliánský kalendář
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:

(22 - 11 × (rok % 19)) % 30

Abychom zase zabránili výskytu záporného čísla, pomůžeme si opět konstantou, nyní postačí přičítat 180. Výsledek pak vypadá takto:

b = 202 - 11 × (rok % 19)
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:

depaktacyklický
úplněk
472716. duben
482617. duben
4925/2517/18. duben
502418. 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:

je-li d rovno 50, pak d = d - 1

S ohledem na vypuštěných deset dnů musíme upravit i vzorec na určení dne týdne cyklického úplňku.

e = (rok + rok / 4 + d - 10) % 7

Zbytek je stejný:

Carterův algoritmus pro roky 1583 až 1699
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:

b = 204 - 11 × (rok % 19)

Výraz ve výpočtu dne týdne se zmenší o sluneční opravu, tedy o 3:

e = (rok + rok / 4 + d - 13) % 7

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:

Carterův algoritmus pro roky 1900 až 2099
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.

Carterův algoritmus pro všechny roky gregoriánského kalendáře
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í.

Další informace:

Kalendáře Helma - nástěnný, stolní i pracovní kalendář Diáře Helma - diář a zápisník
Válka na Ukrajině: 1002.den
Nahoru