Calcular a data da Páscoa

13

Sua função ou programa deve levar um ano como entrada e retornar (ou imprimir) a data (no calendário gregoriano) dos anos da Páscoa (não a Páscoa Ortodoxa Oriental). A data retornada deve ser formatada de acordo com a ISO 8601, mas com suporte para anos maiores que 9999 (como 312013-04-05 ou 20010130 ) e só precisa trabalhar com anos maiores ou iguais a 1583 (o ano do adoção do calendário gregoriano) e anos menores ou iguais a 5701583 (como é quando a sequência das datas da Páscoa começa a se repetir).

Exemplos:

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

O uso de funções internas para retornar a data da páscoa é chato e, portanto, não é permitido. A resposta mais curta (em caracteres) vence.

Recursos:

Para s
fonte
Você percebe que alguns idiomas têm uma função interna para fazer isso?
Peter Taylor
Tal como? O único que eu conheço é o PHP, mas as funções easter_date e easter_days são bastante limitadas, easter_date só funciona por anos após 1970 e easter_days não retorna a quantidade correta de dias para os anos anteriores a 1753. Mas vou editar a pergunta proibir o uso de tais funções.
quer
1
Então, isso é Gregoriano e NÃO Juliano? Além disso, eu não sou católico, o que é a "tradição católica?"
Jdstankosky
2
Mais funções
SeanC 09/04

Respostas:

3

GolfScript (85 caracteres)

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

Uso da amostra:

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

Observe que isso usa um algoritmo diferente da maioria das respostas atuais. Para ser específico, adaptei o algoritmo atribuído a Lichtenberg no recurso vinculado por Sean Cheshire em um comentário sobre a questão.

O algoritmo original, assumindo tipos sensíveis (ou seja, não números do JavaScript) e com uma adaptação para fornecer o mês * 31 + dia (usando o deslocamento do dia de 0), é

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

Extraí uma subexpressão comum e fiz outras otimizações para reduzir a

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

Essa abordagem possui operações aritméticas um pouco mais do que a outra (algoritmo 20-op de Al Petrofsky), mas possui constantes menores; O GolfScript não precisa se preocupar com os parênteses extras porque é baseado em pilha e, como cada valor intermediário no meu layout otimizado é usado precisamente duas vezes, ele se encaixa perfeitamente na limitação do GolfScript de fácil acesso aos três principais itens da pilha.

Peter Taylor
fonte
Ele tem um pequeno problema: quando a data da Páscoa fica entre 1 de abril e 10 de abril, ele retorna datas como 1725041, quando deveria retornar 17250401. Mas votou pela abordagem diferente!
Fors
@Fors, oops. Agora consertado.
22613 Peter Peter Taylor
5

Python 2 - 125 120 119 caracteres

Esta é a resposta de Fors descaradamente portada para Python.

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

Editar : última linha alterada de print"%d-0%d-%02d"%(y,b/31,b%31+1)para salvar 5 caracteres. Eu adoraria representar 10000como 1e4, mas isso produziria um ponto flutuante que requer uma ligação para int.

Edit2 : Obrigado a Peter Taylor por mostrar como se livrar disso 10000e salvar 1 personagem.

Steven Rumbalski
fonte
1
Se você dividir 10000, 100*100poderá colocar a última linha na forma de Horner como (y*100+b/31)*100+b%31+1. O parêntese inicial permite remover o espaço depois printe você pode extrair as três instâncias de 100para uma variável para uma economia geral de 1 caractere.
Peter Taylor
@ PeterTaylor: Excelente sugestão. Atualizei minha resposta.
Steven Rumbalski
Você pode torná-lo uma função e(y)e salvar alguns bytes
sagiksp
4

PHP 154

150 caracteres se eu alternar para AAAAMMDD em vez de AAAA-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";

Com quebras de linha:

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

Uso: php easter.php 1997
Saída:1997-03-30

Uso: php easter.php 2001
Saída:2001-04-15

jdstankosky
fonte
1
Ótimo algoritmo de golfe, código de golfe não tão bom. Tomei a liberdade de cortar 18 bytes:<?=$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
Não atende ao formato de saída. O zero à esquerda do dia está faltando, quando necessário. Por exemplo, para o ano 1725, ele produz em 1725-04-1vez de 1725-04-01.
Christoph
4

dc: 106 caracteres

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

Uso:

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

Isso deve ser reduzido usando 'd' e 'r' em vez de todas as cargas e armazenamentos.

Para s
fonte
3

C: 151 148 caracteres

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

E o mesmo código, mas melhor formatado:

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

Existem muitos algoritmos para o cálculo da data da Páscoa, mas apenas alguns deles são adequados para o código de golfe.

Para s
fonte
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))}

Inspirado na solução PHP de @ jdstankosky ... Fornece resultado AAAAMMDD ...

Agora reduzido para:

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

Agora pede entrada ... reduziu a seqüência literal de "0" para 0 e deixou a digitação solta trabalhar para minha vantagem! :)

Reduzido ainda mais para levar em consideração o 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
fonte
2

APL 132

Esse algoritmo calcula o número de dias que a Páscoa fica em relação ao início de março. A data é retornada no formato AAAAMMDD, conforme permitido na pergunta:

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] 

Tomando os casos de teste originais:

      E 2013
20130331
      E 1583
15830410
      E 3029
30290322
      E 1789
17890412         
Graham
fonte
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

Experimente online!

Usa o algoritmo "Emended Gregorian Easter" (Al Petrofsky) no segundo link de recurso. Estranhamente, ele falha no ano 5701583 (e, aparentemente, apenas neste ano), prevendo a Páscoa como uma semana antes. Imprime a data no YYYYYYYMMDDformato, com alguns espaços à esquerda, se o ano tiver menos de sete dígitos.

rafa11111
fonte