计算复活节的日期


13

您的函数或程序应以一年作为输入,并返回(或打印)该年复活节(而不是东正教复活节)的日期(在公历中)。返回的日期应根据ISO 8601进行格式化,但要支持大于9999的年份(例如312013-04-0520010130),并且只需要使用大于或等于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年之前的正确天数。但是我将编辑问题禁止使用此类功能。
Fors


1
所以这是格里高利而非朱利安?另外,我不是天主教徒,什么是“天主教传统”?
jdstankosky

Answers:


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

请注意,这对大多数当前答案使用了不同的算法。具体来说,我对Sean Cheshire在对该问题的评论中链接的资源中改编了归因于Lichtenberg的算法。

假定合理的类型(即不是JavaScript的数字)并经过修改以给出month * 31 + day(使用天偏移为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

这种方法比另一种方法(Al Petrofsky的20-op算法)具有更多的算术运算,但是它的常数较小。GolfScript无需担心多余的括号,因为它是基于堆栈的,并且由于我的优化布局中的每个中间值都被精确地使用了两次,因此与GolfScript易于访问堆栈中前三项的限制非常吻合。


它有一个小问题,当复活节的日期在4月1日到4月10日之间时,它会返回诸如1725041之类的日期,而当它应返回17250401时。但是赞成采用其他方法!
2013年

@Fors,哎呀。现在已修复。
彼得·泰勒

5

蟒2 - 125 120 119个字符

这是Fors无耻地移植到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个字符。我本来希望将其表示100001e4,但这样会产生浮点数,因此需要调用int

Edit2:感谢Peter Taylor展示了如何摆脱它10000并节省1个字符。


1
如果分手10000100*100您可以将最后一行放在Horner的形式中(y*100+b/31)*100+b%31+1。前导括号使您可以删除后面的空格print,并且可以将的三个实例拉到100一个变量中,从而总共节省了1个字符。
彼得·泰勒

@PeterTaylor:很好的建议。更新了我的答案。
Steven Rumbalski

您可以使其功能e(y)并保存一些字节
sagiksp

4

PHP 154

如果我切换到YYYYMMDD而不是YYYY-MM-DD,则为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


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

无法满足输出格式。当天的前导零在需要的地方丢失。例如,它在1725年输出1725-04-1而不是1725-04-01
克里斯多夫(Christoph)

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

受@jdstankosky的PHP解决方案启发...提供YYYYMMDD结果...

现在缩小为:

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

该算法计算相对于三月初的复活节的天数。按照问题中允许的格式,以YYYYMMDD格式返回日期:

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

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

在线尝试!

使用第二个资源链接中的“推荐的Gregorian Easter”算法(Al Petrofsky)。奇怪的是,它在5701583年(显然仅在今年)失败了,并预测复活节要提前一周。以YYYYYYYMMDD格式打印日期,如果年份少于7位,则以空格开头。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.