So my problem is the following:
Given a number X of size and an A (1st number), B(Last number) interval, I have to find the number of all different kind of non decreasing combinations (increasing or null combinations) that I can build.
Example:
Input: "2 9 11"
X = 2 | A = 9 | B = 11
Output: 8
Possible Combinations ->
[9],[9,9],[9,10],[9,11],[10,10],[10,11],[11,11],[10],[11].
Now, If it was the same input, but with a different X, line X = 4, this would change a lot...
[9],[9,9],[9,9,9],[9,9,9,9],[9,9,9,10],[9,9,9,11],[9,9,10,10]...
Your problem can be reformulated to simplify to just two parameters
X and N = B - A + 1 to give you sequences starting with 0 instead of A.
If you wanted exactly X numbers in each item, it is simple combination with repetition and the equation for that would be
x_of_n = (N + X - 1)! / ((N - 1)! * X!)
so for your first example it would be
X = 2
N = 11 - 9 + 1 = 3
x_of_n = 4! / (2! * 2!) = 4*3*2 / 2*2 = 6
to this you need to add the same with X = 1 to get x_of_n = 3, so you get the required total 9.
I am not aware of simple equation for the required output, but when you expand all the equations to one sum, there is a nice recursive sequence, where you compute next (N,X) from (N,X-1) and sum all the elements:
S[0] = N
S[1] = S[0] * (N + 1) / 2
S[2] = S[1] * (N + 2) / 3
...
S[X-1] = S[X-2] * (N + X - 1) / X
so for the second example you give we have
X = 4, N = 3
S[0] = 3
S[1] = 3 * 4 / 2 = 6
S[2] = 6 * 5 / 3 = 10
S[3] = 10 * 6 / 4 = 15
output = sum(S) = 3 + 6 + 10 + 15 = 34
so you can try the code here:
function count(x, a, b) {
var i,
n = b - a + 1,
s = 1,
total = 0;
for (i = 0; i < x; i += 1) {
s *= (n + i) / (i + 1); // beware rounding!
total += s;
}
return total;
}
console.log(count(2, 9, 11)); // 9
console.log(count(4, 9, 11)); // 34
Update: If you use a language with int types (JS has only double),
you need to use s = s * (n + i) / (i + 1) instead of *= operator to avoid temporary fractional number and subsequent rounding problems.
Update 2: For a more functional version, you can use a recursive definition
function count(x, n) {
return n < 1 || x < 1 ? 0 : 1 + count(n - 1, x) + count(n, x - 1);
}
where n = b - a + 1
I have a dataframe named flow with over 17,000 entries which contains daily water quality days for about 50 years. I have a column that has the jday (day of the year) of each entry but now I want to assign each entry a season from 1 to 4 (winter, spring, fall, summer). This is what I have so far:
> for(i in flow){
+ if (flow$jdays[i] <= 80 | flow$jdays[i]>355){
+ flow$season [i] <- 1
+ } else if (flow$jdays [i] > 80 & flow$jdays [i]<= 172){
flow$season [i] <- 2
+ }
+ else if(flow$jdays [i] > 172 & flow$jdays [i]<= 264){
+ flow$season [i] <- 3
+ }
+ else{
+ flow$season [i] <- 4
+ }
+ }
I keep getting the following message:
Error in if (flow$jdays[i] <= 80 | flow$jdays[i] > 355) { :
argument is of length zero
this may be better approach,
flow$season<-ifelse(flow$jdays<=80 | flow$jdays>355 ,1,
ifelse(flow$jdays<=172,2,
ifelse(flow$jdays<=264,3,4)))
This is in error:
for(i in flow){
Change to:
for(in in seq(nrow(flow))){
A vectorized solution using ifelse:
transform(flow, season=
ifelse (jdays <= 80 | jdays>355, 1,
ifelse(jdays <= 172,2,
ifelse(jdays <= 264, 3, 4))))
I need to optimize the following to find the maximum value for r1:
ad = 0.95*M_D + 0.28*G_D + 0.43*S_D + 2.25*Q_D
as = 0.017*M_A + 0.0064*G_A + 0.0076*S_A + 0.034*Q_A
ccb = 0.0093*M_CC+ 0.0028*G_CC + 0.0042*S_CC + 0.0186*Q_CC
ccd = 0.0223*M_CD + 0.0056*G_CD + 0.0078*S_CD + 0.0446*Q_CD
apb = 1.28*M_P + 2.56*Q_P
r1=(1+ccb*(1+ccd))*ad*as*100/(130-apb)
subject to the following constraints:
0 <= M_CD <= M_CC <= M_A <= M_D <= M_P <= 9
0 <= G_CD <= G_CC <= G_A <= G_D <= 9
0 <= S_CD <= S_CC <= S_A <= S_D <= 9
0 <= Q_CD <= Q_CC <= Q_A <= Q_D <= Q_P <= 3
The approach I've tried before doesn't work very well and I'm hoping to find a better solution.
Once the problem is stated correctly you maybe able to firstly map the parameters to lower and
upper bounds of [0,1]. You can then implement the inequalities inside your function and optimise using an algorithm which accepts basic lower and upper bound constraints. nlminb could be used but the vignette suggests the algorithm used may not be the best.
UPDATE:
With OP revised function
dumFun <- function(p){
p[1] -> M_CD; p[2] -> M_CC; p[3] -> M_A; p[4] -> M_D; p[5] -> M_P;
M_P <- 9*M_P; M_D <- M_P*M_D; M_A <- M_D*M_A; M_CC <- M_A*M_CC; M_CD <- M_CC*M_CD;
p[6] -> G_CD; p[7] -> G_CC; p[8] -> G_A; p[9] -> G_D;
G_D <- 9*G_D; G_A <- G_D*G_A; G_CC <- G_A*G_CC; G_CD <- G_CC*G_CD;
p[10] -> S_CD; p[11] -> S_CC; p[12] -> S_A; p[13] -> S_D;
S_D <- 9*S_D; S_A <- S_D*S_A; S_CC <- S_A*S_CC; S_CD <- S_CC*S_CD;
p[14] -> Q_CD; p[15] -> Q_CC; p[16] -> Q_A; p[17] -> Q_D; p[18] -> Q_P;
Q_P <- 3*Q_P; Q_D <- Q_P*Q_D; Q_A <- Q_D*Q_A; Q_CC <- Q_A*Q_CC; Q_CD <- Q_CC*Q_CD;
ad = 0.95*M_D + 0.28*G_D + 0.43*S_D + 2.25*Q_D
as = 0.017*M_A + 0.0064*G_A + 0.0076*S_A + 0.034*Q_A
ccb = 0.0093*M_CC+ 0.0028*G_CC + 0.0042*S_CC + 0.0186*Q_CC
ccd = 0.0223*M_CD + 0.0056*G_CD + 0.0078*S_CD + 0.0446*Q_CD
apb = 1.28*M_P + 2.56*Q_P
r1=(1+ccb*(1+ccd))*ad*as*100/(130-apb)
-r1
}
require(minqa)
p <- rep(.1, 18)
bobyqa(p, dumFun, lower = rep(0, length(p)), upper = rep(1, length(p)))
parameter estimates: 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
objective: -9.65605526502482
number of function evaluations: 97
>
I finally solved my problem not with vectorization but with C. My program containing 14nested loops executes 100 to 1000 times faster with C than with R ! Which is sad because I didn't learn anything new from that and it prooves that R can be pretty useless on some problems but what can we do.
I have a large vector of percentages (0-100) and I am trying to count how many of them are in
specific 20% buckets (<20, 20-40, 40-60,60-80,80-100). The vector has length 129605 and there are no
NA values. Here's my code:
x<-c(0,0,0,0,0)
for(i in 1: length(mail_return))
{
if (mail_return[i]<=20)
{
x[1] = x[1] + 1
}
if (mail_return[i]>20 && mail_return[i]<=40)
{
x[2] = x[2] + 1
}
if (mail_return[i]>40 && mail_return[i]<=60)
{
x[3] = x[3] + 1
}
if (mail_return[i]>60 && mail_return[i]<=80)
{
x[4] = x[4] + 1
}
else
{
x[5] = x[5] + 1
}
}
But sum(x) is giving me length 133171. Shouldn't it be the length of the vector, 129605? What's wrong?
I like findInterval for these sorts of tasks:
x <- c(1,2,3,20,21,22,40,41,42,60,61,62,80,81,82)
table(findInterval(x,c(0,20,40,60,80)))
1 2 3 4 5
3 3 3 3 3
The reason for the bad count is that
x[5] effectively counts every occurrence which doesn't satisfy the condition mail_return[i]>60 && mail_return[i]<=80,
i.e. counting items that are > 80 (as you would expect), but also counting anew items that are <= 60 (outch! that the bug!).
You can replace...
if (mail_return[i]>60 && mail_return[i]<=80)
{
x[4] = x[4] + 1
}
else
{
x[5] = x[5] + 1
}
by...
if (mail_return[i]>60 && mail_return[i]<=80)
{
x[4] = x[4] + 1
}
if (mail_return[i] >80)
{
x[5] = x[5] + 1
}
...to fix things.
But as hinted in other answers, there are better idioms to find counts (such as table(findInterval(...)) ) which do not require such longhand code (and which are more efficient).
So, here's a funny little programming challenge. I was writing a quick method to determine all the market holidays for a particular year, and then I started reading about Easter and discovered just how crazy* the logic is for determining its date--the first Sunday after the Paschal Full Moon following the spring equinox! Does anybody know of an existing function to calculate the date of Easter for a given year?
Granted, it's probably not all that hard to do; I just figured I'd ask in case somebody's already done this. (And that seems very likely.)
UPDATE: Actually, I'm really looking for the date of Good Friday (the Friday before Easter)... I just figured Easter would get me there. And since I'm in the U.S., I assume I'm looking for the Catholic Easter? But perhaps someone can correct me on that if I'm wrong.
*By "crazy" I meant, like, involved. Not anything offensive...
Python: using dateutil's easter() function.
>>> from dateutil.easter import *
>>> print easter(2010)
2010-04-04
>>> print easter(2011)
2011-04-24
The functions gets, as an argument, the type of calculation you like:
EASTER_JULIAN = 1
EASTER_ORTHODOX = 2
EASTER_WESTERN = 3
You can pick the one relevant to the US.
Reducing two days from the result would give you Good Friday:
>>> from datetime import timedelta
>>> d = timedelta(days=-2)
>>> easter(2011)
datetime.date(2011, 4, 24)
>>> easter(2011)+d
datetime.date(2011, 4, 22)
Oddly enough, someone was iterating this, and published the results in Wikipedia's article about the algorithm:
in SQL Server Easter Sunday would look like this, scroll down for Good Friday
CREATE FUNCTION dbo.GetEasterSunday
( #Y INT )
RETURNS SMALLDATETIME
AS
BEGIN
DECLARE #EpactCalc INT,
#PaschalDaysCalc INT,
#NumOfDaysToSunday INT,
#EasterMonth INT,
#EasterDay INT
SET #EpactCalc = (24 + 19 * (#Y % 19)) % 30
SET #PaschalDaysCalc = #EpactCalc - (#EpactCalc / 28)
SET #NumOfDaysToSunday = #PaschalDaysCalc - (
(#Y + #Y / 4 + #PaschalDaysCalc - 13) % 7
)
SET #EasterMonth = 3 + (#NumOfDaysToSunday + 40) / 44
SET #EasterDay = #NumOfDaysToSunday + 28 - (
31 * (#EasterMonth / 4)
)
RETURN
(
SELECT CONVERT
( SMALLDATETIME,
RTRIM(#Y)
+ RIGHT('0'+RTRIM(#EasterMonth), 2)
+ RIGHT('0'+RTRIM(#EasterDay), 2)
)
)
END
GO
Good Friday is like this and it uses the Easter function above
CREATE FUNCTION dbo.GetGoodFriday
(
#Y INT
)
RETURNS SMALLDATETIME
AS
BEGIN
RETURN (SELECT dbo.GetEasterSunday(#Y) - 2)
END
GO
From here: http://web.archive.org/web/20070611150639/http://sqlserver2000.databases.aspfaq.com/why-should-i-consider-using-an-auxiliary-calendar-table.html
When it came for me to write this (traffic prediction based on day of week and holiday),
I gave up on trying to write it by myself. I found it somewhere on the net. The code was public domain, but...
sigh
see for yourself.
void dateOfEaster(struct tm* p)
{
int Y = p->tm_year;
int a = Y % 19;
int b = Y / 100;
int c = Y % 100;
int d = b / 4;
int e = b % 4;
int f = (b + 8) / 25;
int g = (b - f + 1) / 3;
int h = (19 * a + b - d - g + 15) % 30;
int i = c / 4;
int k = c % 4;
int L = (32 + 2 * e + 2 * i - h - k) % 7;
int m = (a + 11 * h + 22 * L) / 451;
p->tm_mon = ((h + L - 7 * m + 114) / 31 ) - 1;
p->tm_mday = ((h + L - 7 * m + 114) % 31) + 1;
p->tm_hour = 12;
const time_t tmp = mktime(p);
*p = *localtime(&tmp); //recover yday from mon+mday
}
Some questions are better left unasked.
I feel lucky that all moving holidays in my country are a fixed offset from the date of Easter.
The SQL Server function below is more general than the accepted answer
The accepted answer is only correct for the range (inclusive) : 1900-04-15 to 2099-04-12
It uses the algorithm provided by The United States Naval Observatory (USNO)
http://aa.usno.navy.mil/faq/docs/easter.php
CREATE FUNCTION dbo.GetEasterSunday (#Y INT)
RETURNS DATETIME
AS
BEGIN
-- Source of algorithm : http://aa.usno.navy.mil/faq/docs/easter.php
DECLARE #c INT = #Y / 100
DECLARE #n INT = #Y - 19 * (#Y / 19)
DECLARE #k INT = (#c - 17) / 25
DECLARE #i INT = #c - #c / 4 - (#c - #k) / 3 + 19 * #n + 15
SET #i = #i - 30 * (#i / 30)
SET #i = #i - (#i / 28) * (1 - (#i / 28) * (29 / (#i + 1)) * ((21 - #n) / 11))
DECLARE #j INT = #Y + #Y / 4 + #i + 2 - #c + #c / 4
SET #j = #j - 7 * (#j / 7)
DECLARE #l INT = #i - #j
DECLARE #m INT = 3 + (#l + 40) / 44
DECLARE #d INT = #l + 28 - 31 * (#m / 4)
RETURN
(
SELECT CONVERT
( DATETIME,
RTRIM(#Y)
+ RIGHT('0'+RTRIM(#m), 2)
+ RIGHT('0'+RTRIM(#d), 2)
)
)
END
GO
VB .NET Functions for Greek Orthodox and Catholic Easter:
Public Shared Function OrthodoxEaster(ByVal Year As Integer) As Date
Dim a = Year Mod 19
Dim b = Year Mod 7
Dim c = Year Mod 4
Dim d = (19 * a + 16) Mod 30
Dim e = (2 * c + 4 * b + 6 * d) Mod 7
Dim f = (19 * a + 16) Mod 30
Dim key = f + e + 3
Dim month = If((key > 30), 5, 4)
Dim day = If((key > 30), key - 30, key)
Return New DateTime(Year, month, day)
End Function
Public Shared Function CatholicEaster(ByVal Year As Integer) As DateTime
Dim month = 3
Dim a = Year Mod 19 + 1
Dim b = Year / 100 + 1
Dim c = (3 * b) / 4 - 12
Dim d = (8 * b + 5) / 25 - 5
Dim e = (5 * Year) / 4 - c - 10
Dim f = (11 * a + 20 + d - c) Mod 30
If f = 24 Then f += 1
If (f = 25) AndAlso (a > 11) Then f += 1
Dim g = 44 - f
If g < 21 Then g = g + 30
Dim day = (g + 7) - ((e + g) Mod 7)
If day > 31 Then
day = day - 31
month = 4
End If
Return New DateTime(Year, month, day)
End Function
The below code determines Easter through powershell:
function Get-DateOfEaster {
param(
[Parameter(ValueFromPipeline)]
$theYear=(Get-Date).Year
)
if($theYear -lt 1583) {
return $null
} else {
# Step 1: Divide the theYear by 19 and store the
# remainder in variable A. Example: If the theYear
# is 2000, then A is initialized to 5.
$a = $theYear % 19
# Step 2: Divide the theYear by 100. Store the integer
# result in B and the remainder in C.
$c = $theYear % 100
$b = ($theYear -$c) / 100
# Step 3: Divide B (calculated above). Store the
# integer result in D and the remainder in E.
$e = $b % 4
$d = ($b - $e) / 4
# Step 4: Divide (b+8)/25 and store the integer
# portion of the result in F.
$f = [math]::floor(($b + 8) / 25)
# Step 5: Divide (b-f+1)/3 and store the integer
# portion of the result in G.
$g = [math]::floor(($b - $f + 1) / 3)
# Step 6: Divide (19a+b-d-g+15)/30 and store the
# remainder of the result in H.
$h = (19 * $a + $b - $d - $g + 15) % 30
# Step 7: Divide C by 4. Store the integer result
# in I and the remainder in K.
$k = $c % 4
$i = ($c - $k) / 4
# Step 8: Divide (32+2e+2i-h-k) by 7. Store the
# remainder of the result in L.
$l = (32 + 2 * $e + 2 * $i - $h - $k) % 7
# Step 9: Divide (a + 11h + 22l) by 451 and
# store the integer portion of the result in M.
$m = [math]::floor(($a + 11 * $h + 22 * $l) / 451)
# Step 10: Divide (h + l - 7m + 114) by 31. Store
# the integer portion of the result in N and the
# remainder in P.
$p = ($h + $l - 7 * $m + 114) % 31
$n = (($h + $l - 7 * $m + 114) - $p) / 31
# At this point p+1 is the day on which Easter falls.
# n is 3 for March and 4 for April.
$DateTime = New-Object DateTime $theyear, $n, ($p+1), 0, 0, 0, ([DateTimeKind]::Utc)
return $DateTime
}
}
$eastersunday=Get-DateOfEaster 2015
Write-Host $eastersunday
Found this Excel formula somewhere
Assuming cell A1 contains year e.g. 2020
ROUND(DATE(A1;4;1)/7+MOD(19*MOD(A1;19)-7;30)*0,14;0)*7-6
Converted to T-SQL lead me to this:
DECLARE #yr INT=2020
SELECT DATEADD(dd, ROUND(DATEDIFF(dd, '1899-12-30', DATEFROMPARTS(#yr, 4, 1)) / 7.0 + ((19.0 * (#yr % 19) - 7) % 30) * 0.14, 0) * 7.0 - 6, -2)
In JS, taken from here.
var epoch=2444238.5,elonge=278.83354,elongp=282.596403,eccent=.016718,sunsmax=149598500,sunangsiz=.533128,mmlong=64.975464,mmlongp=349.383063,mlnode=151.950429,minc=5.145396,mecc=.0549,mangsiz=.5181,msmax=384401,mparallax=.9507,synmonth=29.53058868,lunatbase=2423436,earthrad=6378.16,PI=3.141592653589793,epsilon=1e-6;function sgn(x){return x<0?-1:x>0?1:0}function abs(x){return x<0?-x:x}function fixAngle(a){return a-360*Math.floor(a/360)}function toRad(d){return d*(PI/180)}function toDeg(d){return d*(180/PI)}function dsin(x){return Math.sin(toRad(x))}function dcos(x){return Math.cos(toRad(x))}function toJulianTime(date){var year,month,day;year=date.getFullYear();var m=(month=date.getMonth()+1)>2?month:month+12,y=month>2?year:year-1,d=(day=date.getDate())+date.getHours()/24+date.getMinutes()/1440+(date.getSeconds()+date.getMilliseconds()/1e3)/86400,b=isJulianDate(year,month,day)?0:2-y/100+y/100/4;return Math.floor(365.25*(y+4716)+Math.floor(30.6001*(m+1))+d+b-1524.5)}function isJulianDate(year,month,day){if(year<1582)return!0;if(year>1582)return!1;if(month<10)return!0;if(month>10)return!1;if(day<5)return!0;if(day>14)return!1;throw"Any date in the range 10/5/1582 to 10/14/1582 is invalid!"}function jyear(td,yy,mm,dd){var z,f,alpha,b,c,d,e;return f=(td+=.5)-(z=Math.floor(td)),b=(z<2299161?z:z+1+(alpha=Math.floor((z-1867216.25)/36524.25))-Math.floor(alpha/4))+1524,c=Math.floor((b-122.1)/365.25),d=Math.floor(365.25*c),e=Math.floor((b-d)/30.6001),{day:Math.floor(b-d-Math.floor(30.6001*e)+f),month:Math.floor(e<14?e-1:e-13),year:Math.floor(mm>2?c-4716:c-4715)}}function jhms(j){var ij;return j+=.5,ij=Math.floor(86400*(j-Math.floor(j))+.5),{hour:Math.floor(ij/3600),minute:Math.floor(ij/60%60),second:Math.floor(ij%60)}}function jwday(j){return Math.floor(j+1.5)%7}function meanphase(sdate,k){var t,t2;return 2415020.75933+synmonth*k+1178e-7*(t2=(t=(sdate-2415020)/36525)*t)-155e-9*(t2*t)+33e-5*dsin(166.56+132.87*t-.009173*t2)}function truephase(k,phase){var t,t2,t3,pt,m,mprime,f,apcor=!1;if(pt=2415020.75933+synmonth*(k+=phase)+1178e-7*(t2=(t=k/1236.85)*t)-155e-9*(t3=t2*t)+33e-5*dsin(166.56+132.87*t-.009173*t2),m=359.2242+29.10535608*k-333e-7*t2-347e-8*t3,mprime=306.0253+385.81691806*k+.0107306*t2+1236e-8*t3,f=21.2964+390.67050646*k-.0016528*t2-239e-8*t3,phase<.01||abs(phase-.5)<.01?(pt+=(.1734-393e-6*t)*dsin(m)+.0021*dsin(2*m)-.4068*dsin(mprime)+.0161*dsin(2*mprime)-4e-4*dsin(3*mprime)+.0104*dsin(2*f)-.0051*dsin(m+mprime)-.0074*dsin(m-mprime)+4e-4*dsin(2*f+m)-4e-4*dsin(2*f-m)-6e-4*dsin(2*f+mprime)+.001*dsin(2*f-mprime)+5e-4*dsin(m+2*mprime),apcor=!0):(abs(phase-.25)<.01||abs(phase-.75)<.01)&&(pt+=(.1721-4e-4*t)*dsin(m)+.0021*dsin(2*m)-.628*dsin(mprime)+.0089*dsin(2*mprime)-4e-4*dsin(3*mprime)+.0079*dsin(2*f)-.0119*dsin(m+mprime)-.0047*dsin(m-mprime)+3e-4*dsin(2*f+m)-4e-4*dsin(2*f-m)-6e-4*dsin(2*f+mprime)+.0021*dsin(2*f-mprime)+3e-4*dsin(m+2*mprime)+4e-4*dsin(m-2*mprime)-3e-4*dsin(2*m+mprime),pt+=phase<.5?.0028-4e-4*dcos(m)+3e-4*dcos(mprime):4e-4*dcos(m)-.0028-3e-4*dcos(mprime),apcor=!0),!apcor)throw"Error calculating moon phase!";return pt}function phasehunt(sdate,phases){var adate,k1,k2,nt1,nt2,yy,mm,dd,jyearResult=jyear(adate=sdate-45,yy,mm,dd);for(yy=jyearResult.year,mm=jyearResult.month,dd=jyearResult.day,adate=nt1=meanphase(adate,k1=Math.floor(12.3685*(yy+1/12*(mm-1)-1900)));nt2=meanphase(adate+=synmonth,k2=k1+1),!(nt1<=sdate&&nt2>sdate);)nt1=nt2,k1=k2;return phases[0]=truephase(k1,0),phases[1]=truephase(k1,.25),phases[2]=truephase(k1,.5),phases[3]=truephase(k1,.75),phases[4]=truephase(k2,0),phases}function kepler(m,ecc){var e,delta;e=m=toRad(m);do{e-=(delta=e-ecc*Math.sin(e)-m)/(1-ecc*Math.cos(e))}while(abs(delta)>epsilon);return e}function getMoonPhase(julianDate){var Day,N,M,Ec,Lambdasun,ml,MM,MN,Ev,Ae,MmP,mEc,lP,lPP,NP,y,x,MoonAge,MoonPhase,MoonDist,MoonDFrac,MoonAng,F,SunDist,SunAng;return N=fixAngle(360/365.2422*(Day=julianDate-epoch)),Ec=kepler(M=fixAngle(N+elonge-elongp),eccent),Ec=Math.sqrt((1+eccent)/(1-eccent))*Math.tan(Ec/2),Lambdasun=fixAngle((Ec=2*toDeg(Math.atan(Ec)))+elongp),F=(1+eccent*Math.cos(toRad(Ec)))/(1-eccent*eccent),SunDist=sunsmax/F,SunAng=F*sunangsiz,ml=fixAngle(13.1763966*Day+mmlong),MM=fixAngle(ml-.1114041*Day-mmlongp),MN=fixAngle(mlnode-.0529539*Day),MmP=MM+(Ev=1.2739*Math.sin(toRad(2*(ml-Lambdasun)-MM)))-(Ae=.1858*Math.sin(toRad(M)))-.37*Math.sin(toRad(M)),lPP=(lP=ml+Ev+(mEc=6.2886*Math.sin(toRad(MmP)))-Ae+.214*Math.sin(toRad(2*MmP)))+.6583*Math.sin(toRad(2*(lP-Lambdasun))),NP=MN-.16*Math.sin(toRad(M)),y=Math.sin(toRad(lPP-NP))*Math.cos(toRad(minc)),x=Math.cos(toRad(lPP-NP)),toDeg(Math.atan2(y,x)),NP,toDeg(Math.asin(Math.sin(toRad(lPP-NP))*Math.sin(toRad(minc)))),MoonAge=lPP-Lambdasun,MoonPhase=(1-Math.cos(toRad(MoonAge)))/2,MoonDist=msmax*(1-mecc*mecc)/(1+mecc*Math.cos(toRad(MmP+mEc))),MoonAng=mangsiz/(MoonDFrac=MoonDist/msmax),mparallax/MoonDFrac,{moonIllumination:MoonPhase,moonAgeInDays:synmonth*(fixAngle(MoonAge)/360),distanceInKm:MoonDist,angularDiameterInDeg:MoonAng,distanceToSun:SunDist,sunAngularDiameter:SunAng,moonPhase:fixAngle(MoonAge)/360}}function getMoonInfo(date){return null==date?{moonPhase:0,moonIllumination:0,moonAgeInDays:0,distanceInKm:0,angularDiameterInDeg:0,distanceToSun:0,sunAngularDiameter:0}:getMoonPhase(toJulianTime(date))}function getEaster(year){var previousMoonInfo,moonInfo,fullMoon=new Date(year,2,21),gettingDarker=void 0;do{previousMoonInfo=getMoonInfo(fullMoon),fullMoon.setDate(fullMoon.getDate()+1),moonInfo=getMoonInfo(fullMoon),void 0===gettingDarker?gettingDarker=moonInfo.moonIllumination<previousMoonInfo.moonIllumination:gettingDarker&&moonInfo.moonIllumination>previousMoonInfo.moonIllumination&&(gettingDarker=!1)}while(gettingDarker&&moonInfo.moonIllumination<previousMoonInfo.moonIllumination||!gettingDarker&&moonInfo.moonIllumination>previousMoonInfo.moonIllumination);for(fullMoon.setDate(fullMoon.getDate()-1);0!==fullMoon.getDay();)fullMoon.setDate(fullMoon.getDate()+1);return fullMoon}
Then run getEaster(2020); // -> Sun Apr 12 2020