Berechnen Sie das Osterdatum

13

Ihre Funktion oder Ihr Programm sollte ein Jahr als Eingabe benötigen und das Datum (im gregorianischen Kalender) des Osterjahres (nicht des ostorthodoxen Osterjahres) zurückgeben (oder ausdrucken). Das zurückgegebene Datum sollte gemäß ISO 8601 formatiert sein, jedoch mit Unterstützung für Jahre größer als 9999 (z. B. 312013-04-05 oder 20010130 ), und es muss nur mit Jahren größer als oder gleich 1583 (dem Jahr des zurückgegebenen Datums ) arbeiten Annahme des Gregorianischen Kalenders) und Jahre kleiner oder gleich 5701583 (da sich die Abfolge der Ostertermine zu wiederholen beginnt).

Beispiele:

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

Die Verwendung der eingebauten Funktionen zur Rückgabe des Osterdatums ist langweilig und daher unzulässig. Kürzeste Antwort (in Zeichen) gewinnt.

Ressourcen:

Fors
quelle
Ist Ihnen klar, dass einige Sprachen eine integrierte Funktion haben, um dies zu tun?
Peter Taylor
Sowie? Das einzige, was mir bekannt ist, ist PHP, aber die Funktionen easter_date und easter_days sind ziemlich eingeschränkt, easter_date funktioniert nur für Jahre nach 1970 und easter_days gibt für Jahre vor 1753 nicht die richtige Anzahl von Tagen zurück. Aber ich werde die Frage bearbeiten die Verwendung solcher Funktionen zu verbieten.
Fors
1
Das ist also Gregorian und NICHT Julian? Ich bin auch nicht katholisch, was ist die "katholische Tradition"?
Jdstankosky

Antworten:

3

GolfScript (85 Zeichen)

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

Beispielnutzung:

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

Beachten Sie, dass dies einen anderen Algorithmus verwendet als die meisten aktuellen Antworten. Um genau zu sein, habe ich den Algorithmus, der Lichtenberg in der von Sean Cheshire verlinkten Ressource zugeschrieben wird, in einem Kommentar zu der Frage angepasst .

Der ursprüngliche Algorithmus, der vernünftige Typen annimmt (dh keine JavaScript-Zahlen) und mit einer Anpassung, um Monat * 31 + Tag (unter Verwendung des Tagesversatzes von 0) anzugeben, ist

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

Ich habe einen allgemeinen Unterausdruck extrahiert und einige andere Optimierungen vorgenommen, um sie zu reduzieren

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

Dieser Ansatz hat etwas mehr arithmetische Operationen als der andere (Al Petrofskys 20-op-Algorithmus), aber kleinere Konstanten; GolfScript muss sich nicht um zusätzliche Klammern kümmern, da es stapelbasiert ist, und da jeder Zwischenwert in meinem optimierten Layout genau zweimal verwendet wird, passt es gut zu der Einschränkung von GolfScript, dass der Zugriff auf die drei obersten Elemente des Stapels einfach ist.

Peter Taylor
quelle
Es hat ein kleines Problem, wenn das Datum von Ostern zwischen dem 1. April und dem 10. April liegt, es gibt Daten wie 1725041 zurück, wenn es 17250401 zurückgeben sollte. Aber für den anderen Ansatz positiv bewertet!
Fors
@Fors, oops. Jetzt behoben.
Peter Taylor
5

Python 2 - 125 120 119 Zeichen

Dies ist Fors Antwort, die schamlos auf Python portiert wurde.

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

Bearbeiten : Letzte Zeile von geändert print"%d-0%d-%02d"%(y,b/31,b%31+1), um 5 Zeichen zu speichern. Am liebsten hätte ich 10000als dargestellt 1e4, aber das würde einen Gleitkommawert erzeugen, der einen Aufruf von erfordert int.

Edit2 : Danke an Peter Taylor, der gezeigt hat, wie man das loswird 10000und 1 Charakter speichert.

Steven Rumbalski
quelle
1
Wenn Sie sich aufteilen 10000, können 100*100Sie die letzte Zeile in Horners Form als einfügen (y*100+b/31)*100+b%31+1. Mit der führenden Klammer können Sie das Leerzeichen danach entfernen printund die drei Instanzen von 100in eine Variable ziehen, um insgesamt 1 Zeichen zu sparen.
Peter Taylor
@ PeterTaylor: Ausgezeichneter Vorschlag. Aktualisiert meine Antwort.
Steven Rumbalski
Sie können es zu einer Funktion machen e(y)und ein paar Bytes
speichern
4

PHP 154

150 Zeichen, wenn ich zu JJJJMMTT anstelle von JJJJ-MM-TT wechsle.

<?$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";

Mit Zeilenumbrüchen:

<?
$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";

Verbrauch: php easter.php 1997
Output:1997-03-30

Verbrauch: php easter.php 2001
Output:2001-04-15

jdstankosky
quelle
1
Tolles Algorithmus-Golfen, nicht so tolles Code-Golfen. Ich habe mir die Freiheit genommen, 18 Bytes abzuschneiden:<?=$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;
Titus
Das Ausgabeformat wird nicht erfüllt. Bei Bedarf fehlt die führende Null für den Tag. ZB für das Jahr 1725 gibt es 1725-04-1statt 1725-04-01.
Christoph
4

dc: 106 zeichen

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

Verwendung:

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

Dies sollte durch die Verwendung von 'd' und 'r' anstelle aller Lasten und Speicher verkürzt werden können.

Fors
quelle
3

C: 151 148 Zeichen

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);}

Und der gleiche Code, aber besser formatiert:

#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);
}

Es gibt furchtbar viele Algorithmen zur Berechnung des Osterdatums, aber nur wenige eignen sich gut zum Code-Golfen.

Fors
quelle
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))}

Inspiriert von @ jdstankoskys PHP-Lösung ... liefert das Ergebnis JJJJMMTT ...

Jetzt eingegrenzt auf:

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

Bittet jetzt um Eingabe ... reduzierte den Literal-String von "0" auf 0 und ließ das lose Tippen zu meinem Vorteil wirken! :)

Wird weiter reduziert, um ES6 zu berücksichtigen ...

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
quelle
2

APL 132

Dieser Algorithmus berechnet die Anzahl der Tage, an denen Ostern relativ zu Anfang März liegt. Das Datum wird im Format JJJJMMTT zurückgegeben, wie in der Frage zulässig:

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] 

Nehmen Sie die Original-Testfälle:

      E 2013
20130331
      E 1583
15830410
      E 3029
30290322
      E 1789
17890412         
Graham
quelle
0

Fortran (GFortran) , 179 Bytes

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

Probieren Sie es online!

Verwendet den Algorithmus "Emended Gregorian Easter" (Al Petrofsky) aus der zweiten Ressourcenverknüpfung. Seltsamerweise scheitert es für das Jahr 5701583 (und anscheinend nur für dieses Jahr) und sagt das Osterfest wie eine Woche zuvor voraus. Gibt das Datum im YYYYYYYMMDDFormat mit einigen führenden Leerzeichen aus, wenn das Jahr weniger als sieben Stellen hat.

rafa11111
quelle