Рассчитать дату Пасхи

13

Ваша функция или программа должны взять год в качестве ввода и вернуть (или распечатать) дату (в григорианском календаре) тех лет Пасхи (а не Восточной православной Пасхи). Возвращенная дата должна быть отформатирована в соответствии с ISO 8601, но с поддержкой для лет, превышающих 9999 (например, 312013-04-05 или 20010130 ), и она должна работать только с годами, большими или равными 1583 (год принятие григорианского календаря), а годы меньше или равны 5701583 (как, например, когда последовательность дат Пасхи начинает повторяться).

Примеры:

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

Использование встроенных функций для возврата даты Пасхи скучно и поэтому запрещено. Самый короткий ответ (в символах) выигрывает.

Ресурсы:

Форс
источник
Вы понимаете, что некоторые языки имеют встроенную функцию для этого?
Питер Тейлор
Такие как? Единственное, что мне известно, это PHP, но функции easter_date и easter_days довольно ограничены, easter_date работает только в течение нескольких лет после 1970 года, а easter_days не возвращает правильное количество дней в течение лет до 1753 года. Но я отредактирую вопрос запретить использование таких функций.
Форс
1
ресурс: en.wikipedia.org/wiki/Computus#Algorithms
Джон Дворжак,
1
Так это григорианский а не юлианский? Кроме того, я не католик, что такое "католическая традиция"?
jdstankosky

Ответы:

3

GolfScript (85 символов)

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

Пример использования:

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

Обратите внимание, что он использует другой алгоритм для большинства текущих ответов. Чтобы быть точным, я адаптировал алгоритм, приписываемый Лихтенбергу в ресурсе, связанном Шоном Чеширом в комментарии к вопросу.

Исходный алгоритм, предполагающий разумные типы (т.е. не числа JavaScript) и с адаптацией, чтобы дать месяц * 31 + день (используя смещение дня 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

Я извлек общее подвыражение и сделал некоторые другие оптимизации, чтобы уменьшить

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

У этого подхода немного больше арифметических операций, чем у другого (20-операционный алгоритм Ала Петрофски), но он имеет меньшие константы; GolfScript не нужно беспокоиться о лишних скобках, потому что он основан на стеке, и поскольку каждое промежуточное значение в моем оптимизированном макете используется точно дважды, это прекрасно согласуется с ограничением GolfScript легкого доступа к верхним трем элементам в стеке.

Питер Тейлор
источник
У него есть небольшая проблема, когда дата Пасхи лежит между 1 апреля и 10 апреля, он возвращает даты, такие как 1725041, когда он должен возвратить 17250401. Но голосовал за другой подход!
Форс
@Fors, ой. Сейчас исправлено.
Питер Тейлор
5

Python 2 - 125 120 119 символов

Это ответ Форса, бесстыдно перенесенный на 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

Изменить : Изменена последняя строка, print"%d-0%d-%02d"%(y,b/31,b%31+1)чтобы сохранить 5 символов. Я хотел бы представлять 10000как 1e4, но это привело бы к плавающей запятой, требующей вызова int.

Edit2 : Спасибо Peter Taylor за то, что показали, как избавиться от этого 10000и сохранить 1 персонаж.

Стивен Румбальский
источник
1
Если вы расстались 10000, 100*100вы можете поместить последнюю строку в форму Хорнера как (y*100+b/31)*100+b%31+1. Начальная скобка позволяет вам удалить пробел после print, и вы можете вытащить три экземпляра 100переменной в общую экономию 1 символа.
Питер Тейлор,
@PeterTaylor: Отличное предложение. Обновил мой ответ.
Стивен Румбальски
Вы можете сделать это функцией e(y)и сохранить несколько байтов
sagiksp
4

PHP 154

150 символов, если я переключусь на ГГГГММДД вместо ГГГГ-ММ-ДД.

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

С переносами строк:

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

Использование: php easter.php 1997
Выход:1997-03-30

Использование: php easter.php 2001
Выход:2001-04-15

jdstankosky
источник
1
Отличный алгоритм игры в гольф, не очень хороший код для игры в гольф. Я взял свободу отрубить 18 байтов:<?=$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;
Тит
Не соответствует выходному формату. Ведущий ноль для дня отсутствует там, где это необходимо. Например, за 1725 год он выводит 1725-04-1вместо 1725-04-01.
Кристоф
4

DC: 106 символов

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

Использование:

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

Это должно быть в состоянии быть сокращено, используя 'd' и 'r' вместо всех загрузок и хранилищ.

Форс
источник
3

C: 151 148 символов

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

И тот же код, но лучше отформатированный:

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

Существует ужасно много алгоритмов для вычисления даты Пасхи, но только некоторые из них хорошо подходят для игры в гольф кода.

Форс
источник
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))}

Вдохновленный решением PHP @ jdstankosky ... Предоставляет результат ГГГГММДД ...

Теперь сужается до:

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

Теперь запрашивает ввод ... уменьшил буквенную строку от "0" до 0 и позволил свободному вводу работать в мою пользу! :)

Снизить дальше, чтобы принять во внимание 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)

Уолли Уэст
источник
2

APL 132

Этот алгоритм вычисляет количество дней, в течение которых Пасха находится относительно начала марта. Дата возвращается в формате ГГГГММДД, как это разрешено в вопросе:

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] 

Взятие оригинальных тестовых случаев:

      E 2013
20130331
      E 1583
15830410
      E 3029
30290322
      E 1789
17890412         
Грэхем
источник
0

Фортран (GFortran) , 179 байтов

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

Попробуйте онлайн!

Использует алгоритм «Исправленная григорианская пасха» (Аль Петрофски) из ссылки на второй ресурс. Как ни странно, он проваливается на 5701583 год (и, видимо, только на этот год), предсказывая Пасху на неделю раньше. Печатает дату в YYYYYYYMMDDформате с некоторыми начальными пробелами, если год содержит менее семи цифр.

rafa11111
источник