Oblicz datę Wielkanocy

13

Twoja funkcja lub program powinien zająć rok jako dane wejściowe i zwrócić (lub wydrukować) datę (w kalendarzu gregoriańskim) tych lat Wielkanocy (nie Wielkanoc prawosławna). Zwrócona data powinna być sformatowana zgodnie z ISO 8601, ale ze wsparciem dla lat większych niż 9999 (takich jak 312013-04-05 lub 20010130 ) i musi działać tylko z latami dłuższymi lub równymi 1583 (rok przyjęcie kalendarza gregoriańskiego) i lat krótszych lub równych 5701583 (kiedy to sekwencja dat wielkanocnych zaczyna się powtarzać).

Przykłady:

e(5701583) = 5701583-04-10
e(2013)    = 2013-03-31
e(1583)    = 1583-04-10
e(3029)    = 30290322
e(1789)    = 17890412
e(1725)    = 17250401

Korzystanie z wbudowanych funkcji do zwracania daty Wielkanocy jest nudne i dlatego jest zabronione. Najkrótsza odpowiedź (w postaciach) wygrywa.

Zasoby:

Fors
źródło
Czy zdajesz sobie sprawę, że niektóre języki mają do tego wbudowaną funkcję?
Peter Taylor,
Jak na przykład? Jedyne, o czym wiem, to PHP, ale funkcje easter_date i easter_days są dość ograniczone, easter_date działa tylko przez lata po 1970 roku, a easter_days nie zwraca prawidłowej liczby dni w latach przed 1753. Ale zmienię pytanie zabronić korzystania z takich funkcji.
Fors
1
Więc to jest Gregorian, a NIE Julian? Poza tym nie jestem katolikiem, czym jest „tradycja katolicka”?
jdstankosky
2
Więcej funkcji
SeanC

Odpowiedzi:

3

GolfScript (85 znaków)

~:^100/.)3*4/.@8*13+25/-^19%.19*15+@+30%.@11/+29/23--.@-^.4/++7%97--^[email protected]/100*\31%)+

Przykładowe użycie:

$ golfscript.rb codegolf11132.gs <<<2013
20130331

Zauważ, że używa to innego algorytmu niż większość obecnych odpowiedzi. Mówiąc ściślej, dostosowałem algorytm przypisany Lichtenbergowi w zasobie powiązanym przez Seana Cheshire w komentarzu do pytania.

Oryginalny algorytm, zakładający rozsądne typy (tj. Nie liczby JavaScript) i z adaptacją, aby dać miesiąc * 31 + dzień (z przesunięciem dnia o 0) to

K = Y/100
M = 15 + (3*K+3)/4 - (8*K+13)/25
S = 2 - (3*K+3)/4
A = Y%19
D = (19*A+M) % 30
R = (D + A/11)/29
OG = 21 + D - R
SZ = 7 - (Y + Y/4 + S) % 7
OE = 7 - (OG-SZ) % 7
return OG + OE + 92

Wyodrębniłem wspólny podwyrażenie i dokonałem innych optymalizacji w celu zredukowania do

K = y/100
k = (3*K+3)/4
A = y%19
D = (19*A+15+k-(8*K+13)/25)%30
G = 23+D-(D+A/11)/29
return 97+G-(G+y+y/4-k)%7

Podejście to ma nieco więcej operacji arytmetycznych niż drugie (algorytm 20 operacji Al Petrofsky'ego), ale ma mniejsze stałe; GolfScript nie musi martwić się dodatkowymi nawiasami, ponieważ jest oparty na stosie, a ponieważ każda wartość pośrednia w moim zoptymalizowanym układzie jest używana dokładnie dwukrotnie, dobrze pasuje do ograniczenia GolfScript w zakresie łatwego dostępu do trzech najlepszych pozycji na stosie.

Peter Taylor
źródło
Ma mały problem, kiedy data Wielkanocy przypada między 1 kwietnia a 10 kwietnia, zwraca daty, takie jak 1725041, kiedy powinna zwrócić 17250401. Ale głosowałem za innym podejściem!
Fors
@ Fors, ups. Teraz naprawione.
Peter Taylor
5

Python 2 - 125 120 119 znaków

Oto odpowiedź Forsa bezwstydnie przeniesiona do Pythona.

y=input()
a=y/100*1483-y/400*2225+2613
b=(y%19*3510+a/25*319)/330%29
b=148-b-(y*5/4+a-b)%7
print(y*100+b/31)*100+b%31+1

Edytuj : Zmieniono ostatni wiersz z, print"%d-0%d-%02d"%(y,b/31,b%31+1)aby zapisać 5 znaków. Chciałbym reprezentować 10000jako 1e4, ale spowodowałoby to zmiennoprzecinkowe wymaganie wezwania do int.

Edycja2 : Podziękowania dla Petera Taylora za pokazanie, jak się go pozbyć 10000i uratować 1 postać.

Steven Rumbalski
źródło
1
Jeśli podzielić 10000maksymalnie 100*100można postawić ostatnią linię w postaci Hornera jako (y*100+b/31)*100+b%31+1. Wiodący nawias pozwala usunąć później miejsce printi można wyciągnąć trzy wystąpienia 100zmiennej do ogólnego oszczędności 1 znaku.
Peter Taylor,
@PeterTaylor: Doskonała sugestia. Zaktualizowałem moją odpowiedź.
Steven Rumbalski
Możesz włączyć tę funkcję e(y)i zaoszczędzić kilka bajtów
sagiksp
4

PHP 154

150 znaków, jeśli zmienię na RRRRMMDD zamiast RRRR-MM-DD.

<?$y=$argv[1];$a=$y/100|0;$b=$a>>2;$c=($y%19*351-~($b+$a*29.32+13.54)*31.9)/33%29|0;$d=56-$c-~($a-$b+$c-24-$y/.8)%7;echo$d>31?"$y-04-".($d-31):"$y-03-$d";

Z podziałem linii:

<?
$y = $argv[1];
$a = $y / 100 |0;
$b = $a >> 2;
$c = ($y % 19 * 351 - ~($b + $a * 29.32 + 13.54) * 31.9) / 33 % 29 |0;
$d = 56 - $c - ~($a - $b + $c - 24 - $y / .8) % 7;
echo $d > 31 ? "$y-04-".($d - 31) : "$y-03-$d";

Wykorzystanie: php easter.php 1997
Wyjście:1997-03-30

Wykorzystanie: php easter.php 2001
Wyjście:2001-04-15

jdstankosky
źródło
1
Świetny algorytm golfowy, niezbyt świetny golfowy kod. Wziąłem swobodę, aby odciąć 18 bajtów:<?=$y=$argv[1],"-0",3+$m=($d=56-($c=($y%19*351-~(($a=$y/100|0)*29.32+($b=$a>>2)+13.54)*31.9)/33%29)-~($a-$b+$c-24-$y/.8)%7)>>5,31*$m-$d;
Tytus
Nie spełnia formatu wyjściowego. W razie potrzeby brakuje wiodącego zera na dany dzień. Np. Dla roku 1725 generuje 1725-04-1zamiast 1725-04-01.
Christoph
4

dc: 106 znaków

?[0n]smdndsy100/1483*ly400/2225*-2613+dsa25/319*ly19%3510*+330/29%sb148lb-5ly*4/la+lb-7%-d31/0nn31%1+d9>mp

Stosowanie:

> dc -e "?[0n]smdndsy100/1483*ly400/2225*-2613+dsa25/319*ly19%3510*+330/29%sb148lb-5ly*4/la+lb-7%-d31/0nn31%1+d9>mp"
1725
17250401
>

Powinno to być możliwe do skrócenia za pomocą „d” i „r” zamiast wszystkich obciążeń i zapasów.

Fors
źródło
3

C: 151 148 znaków

y;a;b;main(){scanf("%d",&y);a=y/100*1483-y/400*2225+2613;b=(y%19*3510+a/25*319)/330%29;b=148-b-(y*5/4+a-b)%7;printf("%d-0%d-%02d\n",y,b/31,b%31+1);}

I ten sam kod, ale lepiej sformatowany:

#include <stdio.h>

int y, a, b;

int main() {
    scanf("%d", &y);

    a = y/100*1483 - y/400*2225 + 2613;
    b = (y%19*3510 + a/25*319)/330%29;
    b = 148 - b - (y*5/4 + a - b)%7;

    printf("%d-0%d-%02d\n", y, b/31, b%31 + 1);
}

Istnieje przerażająco wiele algorytmów do obliczania daty Wielkanocy, ale tylko kilka z nich nadaje się do gry w golfa kodu.

Fors
źródło
3

JavaScript 162 156 145

function e(y){alert(y+"0"+((d=56-(c=(y%19*351-~((b=(a=y/100|0)>>2)+a*29.32+13.54)*31.9)/33%29|0)-~(a-b+c-24-y/.8)%7)>(f=31)?4:3)+(d-f>0&d-f<10?0:"")+(d>f?d-f:d))}

Zainspirowany rozwiązaniem PHP @ jdstankosky ... Zapewnia wynik RRRRMMDD ...

Teraz zawęził się do:

alert((y=prompt())+0+((d=56-(c=(y%19*351-~((b=(a=y/100|0)>>2)+a*29.32+13.54)*31.9)/33%29|0)-~(a-b+c-24-y/.8)%7)>(f=31)?4:3)+(d-f>0&d-f<10?0:"")+(d>f?d-f:d))

Teraz prosi o dane wejściowe ... zmniejszyłem literał ciąg „0” do 0 i pozwól luźnemu pisaniu działać na moją korzyść! :)

Zmniejszono dodatkowo, aby uwzględnić ES6 ...

e=y=>y+"0"+((d=56-(c=(y%19*351-31.9*~((b=(a=y/100|0)>>2)+29.32*a+13.54))/33%29|0)-~(a-b+c-24-y/.8)%7)>(f=31)?4:3)+(d-f>0&d-f<10?0:"")+(d>f?d-f:d)

WallyWest
źródło
2

APL 132

Ten algorytm oblicza liczbę dni Wielkanocy w stosunku do początku marca. Data jest zwracana w formacie RRRRMMDD, jak dozwolone w pytaniu:

E y                                                   
(a b)←⌊((3 8×⌊y÷100)+¯5 13)÷4 25                           
c←7|y+(⌊y÷4)-a-e←⌊d-((19×d←30|(227-(11×c)-a-b))+c←19|y)÷543
+/(10*4 2 0)×y,(3+i>31),(61⍴⍳31)[i←e+28-c] 

Biorąc oryginalne przypadki testowe:

      E 2013
20130331
      E 1583
15830410
      E 3029
30290322
      E 1789
17890412         
Graham
źródło
0

Fortran (GFortran) , 179 bajtów

READ*,I
J=I/100*2967-I/400*8875+7961
K=MOD(MOD(I,19)*6060+(MOD(MOD(J/25,59),30)+23)*319-1,9570)/330
L=K+28-MOD(I*5/4+J+K,7)
WRITE(*,'(I7,I0.2,I0.2)')I,(L-1)/31+3,MOD(L-1,31)+1
END

Wypróbuj online!

Wykorzystuje algorytm „Emended Gregorian Easter” (Al Petrofsky) z drugiego łącza zasobów. O dziwo, zawodzi w roku 5701583 (i najwyraźniej tylko w tym roku), przepowiadając Wielkanoc jak tydzień wcześniej. Drukuje datę w YYYYYYYMMDDformacie z kilkoma wiodącymi spacjami, jeśli rok ma mniej niż siedem cyfr.

rafa11111
źródło