Tính ngày lễ Phục sinh


13

Chức năng hoặc chương trình của bạn sẽ mất một năm làm đầu vào và trả lại (hoặc in) ngày (trong lịch Gregorian) của lễ Phục sinh năm đó (không phải là Lễ Phục sinh của Chính thống giáo phương Đông). Ngày được trả lại phải được định dạng theo ISO 8601, nhưng với sự hỗ trợ cho các năm lớn hơn 9999 (chẳng hạn như 312013-04-05 hoặc 20010130 ) và nó chỉ cần hoạt động với số năm lớn hơn hoặc bằng 1583 (năm của thông qua lịch Gregorian) và số năm nhỏ hơn hoặc bằng 5701583 (vì đó là khi chuỗi ngày Phục sinh bắt đầu lặp lại).

Ví dụ:

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

Việc sử dụng các chức năng tích hợp để trả về ngày Phục sinh là nhàm chán và do đó không được phép. Câu trả lời ngắn nhất (bằng ký tự) thắng.

Tài nguyên:


Bạn có nhận ra rằng một số ngôn ngữ có chức năng tích hợp để thực hiện việc này không?
Peter Taylor

Nhu la? Công cụ duy nhất tôi biết là PHP, nhưng các hàm Phục sinh và Phục sinh khá hạn chế, Phục sinh chỉ hoạt động trong nhiều năm sau 1970 và Phục sinh không trả lại số ngày chính xác trong nhiều năm trước 1753. Nhưng tôi sẽ chỉnh sửa câu hỏi không cho phép sử dụng các chức năng đó.
Dành cho


1
Vậy đây là Gregorian và KHÔNG Julian? Ngoài ra, tôi không phải là người Công giáo, "Truyền thống Công giáo là gì?"
jdstankosky

Câu trả lời:


3

GolfScript (85 ký tự)

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

Sử dụng mẫu:

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

Lưu ý rằng điều này sử dụng một thuật toán khác với hầu hết các câu trả lời hiện tại. Để cụ thể, tôi đã điều chỉnh thuật toán được gán cho Lichtenberg trong tài nguyên được liên kết bởi Sean Cheshire trong một nhận xét về câu hỏi.

Thuật toán ban đầu, giả sử các loại hợp lý (không phải là số của JavaScript) và với sự thích ứng để đưa ra tháng * 31 + ngày (sử dụng độ lệch ngày là 0) là

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

Tôi đã trích xuất một biểu thức con phổ biến và thực hiện một số tối ưu hóa khác để giảm xuống

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

Cách tiếp cận này có các phép toán số học nhiều hơn một chút so với cách khác (thuật toán 20-op của Al Petrofsky), nhưng nó có các hằng số nhỏ hơn; GolfScript không cần phải lo lắng về các dấu ngoặc đơn phụ vì nó dựa trên ngăn xếp và vì mỗi giá trị trung gian trong bố cục được tối ưu hóa của tôi được sử dụng chính xác hai lần, nó phù hợp với giới hạn dễ dàng truy cập vào ba mục hàng đầu trên ngăn xếp.


Nó có một vấn đề nhỏ, khi ngày lễ Phục sinh nằm giữa ngày 1 tháng 4 và ngày 10 tháng 4, nó trả về những ngày như 1725041, khi nó sẽ trả về 17250401. Nhưng được ủng hộ cho cách tiếp cận khác!
Dành cho

@Fors, ôi. Bây giờ đã sửa.
Peter Taylor

5

Python 2 - 125 120 119 ký tự

Đây là câu trả lời của Fors được chuyển sang Python một cách đáng xấu hổ.

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

Chỉnh sửa : Thay đổi dòng cuối cùng print"%d-0%d-%02d"%(y,b/31,b%31+1)để lưu 5 ký tự. Tôi rất thích đại diện 10000như 1e4, nhưng điều đó sẽ tạo ra điểm nổi cần có một cuộc gọi đến int.

Edit2 : Cảm ơn Peter Taylor đã chỉ cho bạn cách thoát khỏi điều đó 10000và lưu 1 ký tự.


1
Nếu bạn chia 10000ra, 100*100bạn có thể đặt dòng cuối cùng vào dạng của Horner là (y*100+b/31)*100+b%31+1. Dấu ngoặc đơn hàng đầu cho phép bạn loại bỏ khoảng trắng sau printvà bạn có thể rút ra ba trường hợp của 100một biến để tiết kiệm tổng thể 1 char.
Peter Taylor

@PeterTaylor: Gợi ý tuyệt vời. Cập nhật câu trả lời của tôi.
Steven Rumbalski

Bạn có thể biến nó thành một hàm e(y)và lưu một vài byte
sagiksp

4

PHP 154

150 ký tự nếu tôi chuyển sang YYYYMMDD thay vì YYYY-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";

Với ngắt dòng:

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

Sử dụng: php easter.php 1997
Đầu ra:1997-03-30

Sử dụng: php easter.php 2001
Đầu ra:2001-04-15


1
Thuật toán golf tuyệt vời, không phải là mã golf tuyệt vời. Tôi lấy tự do để cắt 18 byte:<?=$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;
Tít

Thất bại để đáp ứng định dạng đầu ra. Số không hàng đầu trong ngày bị thiếu khi cần thiết. Ví dụ, cho năm 1725, nó xuất ra 1725-04-1thay vì 1725-04-01.
Christoph

4

dc: 106 ký tự

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

Sử dụng:

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

Điều này sẽ có thể được rút ngắn bằng cách sử dụng 'd' và 'r' thay vì tất cả các tải và cửa hàng.


3

C: 151 148 ký tự

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

Và cùng một mã, nhưng được định dạng tốt hơn:

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

Có rất nhiều thuật toán để tính ngày Phục Sinh, nhưng chỉ có một vài trong số chúng rất phù hợp để chơi gôn.


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

Lấy cảm hứng từ giải pháp PHP của @ jdstankosky ... Cung cấp kết quả YYYYMMDD ...

Bây giờ thu hẹp xuống:

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

Bây giờ yêu cầu đầu vào ... giảm chuỗi chữ "0" thành 0 và thả lỏng gõ làm việc để lợi thế của tôi! :)

Giảm hơn nữa để đưa ES6 vào tài khoản ...

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

Thuật toán này tính toán số ngày lễ Phục sinh nằm so với đầu tháng ba. Ngày được trả về ở định dạng YYYYMMDD như được phép trong câu hỏi:

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] 

Lấy các trường hợp thử nghiệm ban đầu:

      E 2013
20130331
      E 1583
15830410
      E 3029
30290322
      E 1789
17890412         

0

Fortran (GFortran) , 179 byte

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

Hãy thử trực tuyến!

Sử dụng thuật toán "Phục sinh Gregorian" (Al Petrofsky) từ liên kết tài nguyên thứ hai. Kỳ lạ thay, nó thất bại trong năm 5701583 (và, rõ ràng, chỉ trong năm nay), dự đoán lễ Phục sinh là một tuần trước đó. In ngày ở YYYYYYYMMDDđịnh dạng, với một số khoảng trắng hàng đầu nếu năm có ít hơn bảy chữ số.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.