I have some diffculty count a(n) = the number of Niven (Harshad) numbers exceeding N - math

Harshad/Niven numbers are positive numbers that are divisible by the sum of their digits. All single-digit numbers are Harshad numbers.
For example, 27 is a Harshad number as 2 + 7 = 9, and 9 is a divisor of 27.Count a(n) = the number of Niven (Harshad) numbers exceeding n (n<=1e12)
We can define the function checkHarshad(n) (Calculate sum of digits of n and check whether n%S(n)), then count the number of Harshad numbers in range [1..n]. But the program just run fast if n <= 1e7
Hiroaki Yamanouchi had a python code that calculate a(10^n), but I don't understand it, and I don't think it's helpful to my problem if n <= 1e12.
def number_of_niven_numbers(digits):
"""
- Count the number of Niven numbers
less than or equal to 10^digits.
"""
N = digits
ret = 0
cnts = [0] * (digits + 1)
for digit_sum in range(1, N * 9 + 1):
curr = [[0] * digit_sum]
curr[0][0] = 1
next_mods = [0] * digit_sum
for i in range(digit_sum):
next_mods[i] = 10 * i % digit_sum
for left_digits in range(N):
left_sum_max = min(9 * left_digits, digit_sum)
next = [[0] * digit_sum for _ in range(min(left_sum_max + 9, digit_sum) + 1)]
for left_sum in range(left_sum_max + 1):
for left_mod in range(digit_sum):
cnt = curr[left_sum][left_mod]
if cnt == 0:
continue
next_mod_base = next_mods[left_mod]
for next_digit in range(min(min(digit_sum, 9), digit_sum - left_sum) + 1):
next_sum = left_sum + next_digit
next_mod = next_mod_base + next_digit
if next_mod >= digit_sum:
next_mod -= digit_sum
next[next_sum][next_mod] += cnt
curr = next
if digit_sum < len(curr):
cnts[left_digits + 1] += curr[digit_sum][0]
return cnts[N] + 1
So, how can we calculate a(n) up to 1e12?

Related

Implementing FFT over finite fields

I would like to implement multiplication of polynomials using NTT. I followed Number-theoretic transform (integer DFT) and it seems to work.
Now I would like to implement multiplication of polynomials over finite fields Z_p[x] where p is arbitrary prime number.
Does it changes anything that the coefficients are now bounded by p, compared to the former unbounded case?
In particular, original NTT required to find prime number N as the working modulus that is larger than (magnitude of largest element of input vector)^2 * (length of input vector) + 1 so that the result never overflows. If the result is going to be bounded by that p prime anyway, how small can the modulus be? Note that p - 1 does not have to be of form (some positive integer) * (length of input vector).
Edit: I copy-pasted the source from the link above to illustrate the problem:
#
# Number-theoretic transform library (Python 2, 3)
#
# Copyright (c) 2017 Project Nayuki
# All rights reserved. Contact Nayuki for licensing.
# https://www.nayuki.io/page/number-theoretic-transform-integer-dft
#
import itertools, numbers
def find_params_and_transform(invec, minmod):
check_int(minmod)
mod = find_modulus(len(invec), minmod)
root = find_primitive_root(len(invec), mod - 1, mod)
return (transform(invec, root, mod), root, mod)
def check_int(n):
if not isinstance(n, numbers.Integral):
raise TypeError()
def find_modulus(veclen, minimum):
check_int(veclen)
check_int(minimum)
if veclen < 1 or minimum < 1:
raise ValueError()
start = (minimum - 1 + veclen - 1) // veclen
for i in itertools.count(max(start, 1)):
n = i * veclen + 1
assert n >= minimum
if is_prime(n):
return n
def is_prime(n):
check_int(n)
if n <= 1:
raise ValueError()
return all((n % i != 0) for i in range(2, sqrt(n) + 1))
def sqrt(n):
check_int(n)
if n < 0:
raise ValueError()
i = 1
while i * i <= n:
i *= 2
result = 0
while i > 0:
if (result + i)**2 <= n:
result += i
i //= 2
return result
def find_primitive_root(degree, totient, mod):
check_int(degree)
check_int(totient)
check_int(mod)
if not (1 <= degree <= totient < mod):
raise ValueError()
if totient % degree != 0:
raise ValueError()
gen = find_generator(totient, mod)
root = pow(gen, totient // degree, mod)
assert 0 <= root < mod
return root
def find_generator(totient, mod):
check_int(totient)
check_int(mod)
if not (1 <= totient < mod):
raise ValueError()
for i in range(1, mod):
if is_generator(i, totient, mod):
return i
raise ValueError("No generator exists")
def is_generator(val, totient, mod):
check_int(val)
check_int(totient)
check_int(mod)
if not (0 <= val < mod):
raise ValueError()
if not (1 <= totient < mod):
raise ValueError()
pf = unique_prime_factors(totient)
return pow(val, totient, mod) == 1 and all((pow(val, totient // p, mod) != 1) for p in pf)
def unique_prime_factors(n):
check_int(n)
if n < 1:
raise ValueError()
result = []
i = 2
end = sqrt(n)
while i <= end:
if n % i == 0:
n //= i
result.append(i)
while n % i == 0:
n //= i
end = sqrt(n)
i += 1
if n > 1:
result.append(n)
return result
def transform(invec, root, mod):
check_int(root)
check_int(mod)
if len(invec) >= mod:
raise ValueError()
if not all((0 <= val < mod) for val in invec):
raise ValueError()
if not (1 <= root < mod):
raise ValueError()
outvec = []
for i in range(len(invec)):
temp = 0
for (j, val) in enumerate(invec):
temp += val * pow(root, i * j, mod)
temp %= mod
outvec.append(temp)
return outvec
def inverse_transform(invec, root, mod):
outvec = transform(invec, reciprocal(root, mod), mod)
scaler = reciprocal(len(invec), mod)
return [(val * scaler % mod) for val in outvec]
def reciprocal(n, mod):
check_int(n)
check_int(mod)
if not (0 <= n < mod):
raise ValueError()
x, y = mod, n
a, b = 0, 1
while y != 0:
a, b = b, a - x // y * b
x, y = y, x % y
if x == 1:
return a % mod
else:
raise ValueError("Reciprocal does not exist")
def circular_convolve(vec0, vec1):
if not (0 < len(vec0) == len(vec1)):
raise ValueError()
if any((val < 0) for val in itertools.chain(vec0, vec1)):
raise ValueError()
maxval = max(val for val in itertools.chain(vec0, vec1))
minmod = maxval**2 * len(vec0) + 1
temp0, root, mod = find_params_and_transform(vec0, minmod)
temp1 = transform(vec1, root, mod)
temp2 = [(x * y % mod) for (x, y) in zip(temp0, temp1)]
return inverse_transform(temp2, root, mod)
vec0 = [24, 12, 28, 8, 0, 0, 0, 0]
vec1 = [4, 26, 29, 23, 0, 0, 0, 0]
print(circular_convolve(vec0, vec1))
def modulo(vec, prime):
return [x % prime for x in vec]
print(modulo(circular_convolve(vec0, vec1), 31))
Prints:
[96, 672, 1120, 1660, 1296, 876, 184, 0]
[3, 21, 4, 17, 25, 8, 29, 0]
However, where I change minmod = maxval**2 * len(vec0) + 1 to minmod = maxval + 1, it stops working:
[14, 16, 13, 20, 25, 15, 20, 0]
[14, 16, 13, 20, 25, 15, 20, 0]
What is the smallest minmod (N in the link above) be in order to work as expected?
If your input of n integers is bound to some prime q (any mod q not just prime will be the same) You can use it as a max value +1 but beware you can not use it as a prime p for the NTT because NTT prime p has special properties. All of them are here:
Translation from Complex-FFT to Finite-Field-FFT
so our max value of each input is q-1 but during your task computation (Convolution on 2 NTT results) the magnitude of first layer results can rise up to n.(q-1) but as we are doing convolution on them the input magnitude of final iNTT will rise up to:
m = n.((q-1)^2)
If you are doing different operations on the NTTs than the m equation might change.
Now let us get back to the p so in a nutshell you can use any prime p that upholds these:
p mod n == 1
p > m
and there exist 1 <= r,L < p such that:
p mod (L-1) = 0
r^(L*i) mod p == 1 // i = { 0,n }
r^(L*i) mod p != 1 // i = { 1,2,3, ... n-1 }
If all this is satisfied then p is nth root of unity and can be used for NTT. To find such prime and also the r,L look at the link above (there is C++ code that finds such).
For example during string multiplication we take 2 strings do NTT on them then convolute the result and iNTT back the result (that is sum of both input sizes). So for example:
99999999999999999999999999999999
*99999999999999999999999999999999
----------------------------------------------------------------
9999999999999999999999999999999800000000000000000000000000000001
the q = 10 and both operands are 9^32 so n=32 hence m = 9*9*32 = 2592 and the found prime is p = 2689. As you can see the result matches so no overflow occurs. However if I use any smaller prime that still fit all the other conditions the result will not match. I used this specifically to stretch the NTT values as much as possible (all values are q-1 and sizes are equal to the same power of 2)
In case your NTT is fast and n is not a power of 2 then you need to zero pad to nearest higher or equal power of 2 size for each NTT. But that should not affect the m value as zero pad should not increase the magnitude of values. My testing proves it so for convolution you can use:
m = (n1+n2).((q-1)^2)/2
where n1,n2 are the raw inputs sizes before zeropad.
For more info about implementing NTT you can check out mine in C++ (extensively optimized):
Modular arithmetics and NTT (finite field DFT) optimizations
So to answer your questions:
yes you can take advantage of the fact that input is mod q but you can not use q as p !!!
You can use minmod = n * (maxval + 1) only for single NTT (or first layer of NTTs) but as you are chaining them with convolution during your NTT usage you can not use that for the final INTT stage !!!
However as I mentioned in the comments easiest is to use max possible p that fits in the data type you are using and is usable for all power of 2 sizes of input supported.
Which basically renders your question irrelevant. The only case I can think of where this is not possible/desired is on arbitrary precision numbers where there is "no" max limit. There are many performance issues binded to variable p as the search for p is really slow (may be even slower than the NTT itself) and also variable p disables many performance optimizations of the modular arithmetics needed making the NTT really slow.

Non Decreasing Number Combinations (Interval)

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

QBasic - How to find this value?

If we have M as follows:
M = 1+2+3+5+6+7+9+10+11+13+...+n
What would be the QBasic program to find M.
I have done the following so far, but is not returning me the expected value
INPUT "ENTER A VALUE FOR N"
SUM = 0
FOR I = 1 TO N
IF I MOD 4 = 0
SUM = SUM + I
NECT I
How should I go about this?
Thanks.
You have mixed the equality operator. Try this:
INPUT "ENTER A VALUE FOR N"
SUM = 0
FOR I = 1 TO N
IF I MOD 4 <> 0
SUM = SUM + I
NEXT I
No need to write a program, or at least no need to use loops.
Sum of first n natural numbers:
sum_1 = n * (n + 1) / 2
Sum of multiples of 4 < n:
sum_2 = 4 * (n / 4) * (n / 4 + 1) / 2 = 2 * (n / 4) * (n / 4 + 1)
The result is sum_1 - sum_2:
sum = sum_1 - sum_2 = n * (n + 1) / 2 - 2 * (n / 4) * (n / 4 + 1)
NB: / = integer division
This snip calculates the sum of integers to n skipping values divisible by 4.
PRINT "Enter upper value";
INPUT n
' calculate sum of all values
FOR l = 1 TO n
x = x + l
NEXT
' remove values divisible by 4
FOR l = 0 TO n STEP 4
x = x - l
NEXT
PRINT "Solution is:"; x

When will this Recurrence Relation repeat

I have this recurrence formula:
P(n) = ( P(n-1) + 2^(n/2) ) % (X)
s.t. P(1) = 2;
where n/2 is computer integer division i.e. floor of x/2
Since i am taking mod X, this relation should repeat at least with in X outputs.
but it can start repeating before that.
How to find this value?
It needn't repeat within x terms, consider x = 3:
P(1) = 2
P(2) = (P(1) + 2^(2/2)) % 3 = 4 % 3 = 1
P(3) = (P(2) + 2^(3/2)) % 3 = (1 + 2) % 3 = 0
P(4) = (P(3) + 2^(4/2)) % 3 = 4 % 3 = 1
P(5) = (P(4) + 2^(5/2)) % 3 = (1 + 4) % 3 = 2
P(6) = (P(5) + 2^(6/2)) % 3 = (2 + 8) % 3 = 1
P(7) = (P(6) + 2^(7/2)) % 3 = (1 + 8) % 3 = 0
P(8) = (P(7) + 2^(8/2)) % 3 = 16 % 3 = 1
P(9) = (P(8) + 2^(9/2)) % 3 = (1 + 16) % 3 = 2
P(10) = (P(9) + 2^(10/2)) % 3 = (2 + 32) % 3 = 1
P(11) = (P(10) + 2^(11/2)) % 3 = (1 + 32) % 3 = 0
P(12) = (P(11) + 2^(12/2)) % 3 = (0 + 64) % 3 = 1
and you see that the period is 4.
Generally (suppose X is odd, it's a bit more involved for even X), let k be the period of 2 modulo X, i.e. k > 0, 2^k % X = 1, and k is minimal with these properties (see below).
Consider all arithmetic modulo X. Then
n
P(n) = 2 + ∑ 2^(j/2)
j=2
It is easier to see when we separately consider odd and even n:
m m
P(2*m+1) = 2 + 2 * ∑ 2^i = 2 * ∑ 2^i = 2*(2^(m+1) - 1) = 2^((n+2)/2) + 2^((n+1)/2) - 2
i=1 i=0
since each 2^j appears twice, for j = 2*i and j = 2*i+1. For even n = 2*m, there's one summand 2^m missing, so
P(2*m) = 2^(m+1) + 2^m - 2 = 2^((n+2)/2) + 2^((n+1)/2) - 2
and we see that the length of the period is 2*k, since the changing parts 2^((n+1)/2) and 2^((n+2)/2) have that period. The period immediately begins, there is no pre-period part (there can be a pre-period for even X).
Now k <= φ(X) by Euler's generalisation of Fermat's theorem, so the period is at most 2 * φ(X).
(φ is Euler's totient function, i.e. φ(n) is the number of integers 1 <= k <= n with gcd(n,k) = 1.)
What makes it possible that the period is longer than X is that P(n+1) is not completely determined by P(n), the value of n also plays a role in determining P(n+1), in this case the dependence is simple, each power of 2 being used twice in succession doubles the period of the pure powers of 2.
Consider the sequence a[k] = (2^k) % X for odd X > 1. It has the simple recurrence
a[0] = 1
a[k+1] = (2 * a[k]) % X
so each value completely determines the next, thus the entire following part of the sequence. (Since X is assumed odd, it also determines the previous value [if k > 0] and thus the entire previous part of the sequence. With H = (X+1)/2, we have a[k-1] = (H * a[k]) % X.)
Hence if the sequence assumes one value twice (and since there are only X possible values, that must happen within the first X+1 values), at indices i and j = i+p > i, say, the sequence repeats and we have a[k+p] = a[k] for all k >= i. For odd X, we can go back in the sequence, therefore a[k+p] = a[k] also holds for 0 <= k < i. Thus the first value that occurs twice in the sequence is a[0] = 1.
Let p be the smallest positive integer with a[p] = 1. Then p is the length of the smallest period of the sequence a, and a[k] = 1 if and only if k is a multiple of p, thus the set of periods of a is the set of multiples of p. Euler's theorem says that a[φ(X)] = 1, from that we can conclude that p is a divisor of φ(X), in particular p <= φ(X) < X.
Now back to the original sequence.
P(n) = 2 + a[1] + a[1] + a[2] + a[2] + ... + a[n/2]
= a[0] + a[0] + a[1] + a[1] + a[2] + a[2] + ... + a[n/2]
Since each a[k] is used twice in succession, it is natural to examine the subsequences for even and odd indices separately,
E[m] = P(2*m)
O[m] = P(2*m+1)
then the transition from one value to the next is more regular. For the even indices we find
E[m+1] = E[m] + a[m] + a[m+1] = E[m] + 3*a[m]
and for the odd indices
O[m+1] = O[m] + a[m+1] + a[m+1] = O[m] + 2*a[m+1]
Now if we ignore the modulus for the moment, both E and O are geometric sums, so there's an easy closed formula for the terms. They have been given above (in slightly different form),
E[m] = 3 * 2^m - 2 = 3 * a[m] - 2
O[m] = 2 * 2^(m+1) - 2 = 2 * a[m+1] - 2 = a[m+2] - 2
So we see that O has the same (minimal) period as a, namely p, and E also has that period. Unless maybe if X is divisible by 3, that is also the minimal (positive) period of E (if X is divisible by 3, the minimal positive period of E could be a proper divisor of p, for X = 3 e.g., E is constant).
Thus we see that 2*p is a period of the sequence P obtained by interlacing E and O.
It remains to be seen that 2*p is the minimal positive period of P. Let m be the minimal positive period. Then m is a divisor of 2*p.
Suppose m were odd, m = 2*j+1. Then
P(1) = P(m+1) = P(2*m+1)
P(2) = P(m+2) = P(2*m+2)
and consequently
P(2) - P(1) = P(m+2) - P(m+1) = P(2*m+2) - P(2*m+1)
But P(2) - P(1) = a[1] and
P(m+2) - P(m+1) = a[(m+2)/2] = a[j+1]
P(2*m+2) - P(2*m+1) = a[(2*m+2)/2] = a[m+1] = a[2*j+2]
So we must have a[1] = a[j+1], hence j is a period of a, and a[j+1] = a[2*j+2], hence j+1 is a period of a too. But that means that 1 is a period of a, which implies X = 1, a contradiction.
Therefore m is even, m = 2*j. But then j is a period of O (and of E), thus a multiple of p. On the other hand, m <= 2*p implies j <= p, and the only (positive) multiple of p satisfying that inequality is p itself, hence j = p, m = 2*p.

Function to return date of Easter for the given year

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

Resources