Реализации алгоритмов/Алгоритм пасхалии: различия между версиями

Добавлены описание задачи, описание алгоритма и реализации на Basic, C, C++, Go, Pascal, Python, Rust
(оформление)
(Добавлены описание задачи, описание алгоритма и реализации на Basic, C, C++, Go, Pascal, Python, Rust)
{{wikipedia|Пасхалия}}
'''Пасха''' (англ. '''Easter''') — христианский праздник воскресения Иисуса Христа, отмечающийся в первое воскресенье после первого полнолуния, наступающего не ранее весеннего равноденствия; таким образом он не привязан к конкретной дате («преходящий праздник»). Под полнолунием и равноденствием понимаются не фактические астрономические явления, а их расчётные даты: полнолуние вычисляется по Метонову циклу, за равноденствие берётся 21 марта (календарное равноденствие для северного полушария).
== [[w:Perl|Perl]] ==
 
: Rich Bowen’s модуль ''Date::Easter'' доступен на сайте CPAN .<ref>{{cite web|title=Date::Easter|url=http://search.cpan.org/~rbow/Date-Easter-1.14/lib/Date/Easter.pm|publisher=CPAN|archiveurl=http://www.webcitation.org/6FcDSMkSb|archivedate=2013-04-04}}</ref>
'''Пасхалия''' (англ. = лат. '''Computus''' — исчисление) — методика расчёта даты празднования Пасхи в том или ином году. В настоящее время большинство православных церквей используют александрийскую пасхалию, опирающуюся на юлианский календарь («старый стиль»), тогда как католическая, а также некоторые православные и протестантские церкви придерживаются григорианской, основанной на общепринятом григорианском календаре. Из-за расхождения между этими календарями (13 дней на сегодня) разница между датами празднования «католической» и «православной» Пасхи в разные годы может составлять 0, 1, 4 или 5 недель.
 
==Описание==
Существуют различные алгоритмы пасхалии. Здесь использован алгоритм григорианской пасхалии неизвестного автора (журнал New York correspondent, 1876) и его адаптация бельгийским математиком-астрономом Жаном Меёсом (франц. Jean Meeus) для александрийской пасхалии (Jean Meeus - Astronomical Algorithms, 1991).
 
'''Дано:''' год
 
'''Найти:''' месяц, день
 
Вычисляется фактор. <code>ЦЕЛ(x)</code> означает целую часть выражения, <code>ОСТ(x / y)</code> — остаток от деления.
 
Александрийская пасхалия:
<syntaxhighlight>
d = ОСТ((ОСТ(год / 19) × 19 + 15) / 30)
factor = d + ОСТ(((ОСТ(год / 4) × 2) + (ОСТ(год / 7) × 4) + 34 − d) / 7) + 114
</syntaxhighlight>
 
Григорианская пасхалия:
<syntaxhighlight>
a = ОСТ(год / 19)
b = ЦЕЛ(год / 100)
c = ОСТ(год / 100)
h = ОСТ((19 × a + b − ЦЕЛ(b / 4) − ЦЕЛ((b − ЦЕЛ((b + 8) / 25) + 1) / 3) + 15) / 30)
l = ОСТ((32 + (ОСТ(b / 4) + ЦЕЛ(c / 4)) × 2 − h − ОСТ(c / 4)) / 7)
factor = h + l − ЦЕЛ((11 × (h + 2 × l) + a) / 451) × 7 + 114
</syntaxhighlight>
 
Месяц и день Пасхи вычисляются из фактора:
 
<syntaxhighlight>
месяц = ЦЕЛ(factor / 31)
день = ОСТ(factor / 31) + 1
</syntaxhighlight>
 
Для григорианской пасхи найденные значения определяют григорианскую дату, а для александрийской — юлианскую.
 
==Реализации==
===[[w:PowerBASIC|PowerBASIC]], [[w:QBASIC|QBASIC]], [[w:QuickBasic|QuickBasic]] версий 4.X, [[w:Visual Basic|Visual Basic]] версий ≤ 6.0, [[w:Visual Basic for Applications|Visual Basic для приложений]]===
<syntaxhighlight lang="vb">
' computus.bas
 
' ComputusGetEaster вычисляет по данному фактору месяц и день Пасхи (приватная функция).
Sub ComputusGetEaster(factor As Integer, month As Integer, day As Integer)
month = factor \ 31
day = factor Mod 31 + 1
End Sub
 
' ComputusGetAlexandrian вычисляет для данного года месяц и день православной Пасхи (юлианская дата).
Sub ComputusGetAlexandrian(year As Integer, month As Integer, day As Integer)
Dim d As Integer
d = (year Mod 19 * 19 + 15) Mod 30
ComputusGetEaster d + (year Mod 4 * 2 + year Mod 7 * 4 + 34 - d) Mod 7 + 114, month, day
End Sub
 
' ComputusGetGregorian вычисляет для данного года месяц и день католической Пасхи (григорианская дата).
Sub ComputusGetGregorian(year As Integer, month As Integer, day As Integer)
Dim a As Integer, b As Integer, c As Integer, h As Integer, l As Integer
a = year Mod 19
b = year \ 100
c = year Mod 100
h = (19 * a + b - b \ 4 - (b - (b + 8) \ 25 + 1) \ 3 + 15) Mod 30
l = (32 + (b Mod 4 + c \ 4) * 2 - h - c Mod 4) Mod 7
ComputusGetEaster h + l - (11 * (h + l + l) + a) \ 451 * 7 + 114, month, day
End Sub
</syntaxhighlight>
Пример использования:
<syntaxhighlight lang="vb">
' comptest.bas
 
' PrintDate выводит дату в формате:
' К: ГГГГ-ММ-ДД
' где К — название календаря, ГГГГ — год, ММ — двузначный номер месяца, ДД — двузначное число.
Sub PrintDate(calendar As String, year As Integer, month As Integer, day As Integer)
Print calendar; ": ";
Print year; "-";
If month < 10 Then Print "0";
Print Str(month); "-";
If day < 10 Then Print "0";
Print Str(day)
End Sub
 
' Для Visual Basic добавить здесь Sub Main
 
Dim year As Integer
 
Input "Year", year
 
Dim month As Integer, day As Integer
 
ComputusGetAlexandrian year, month, day
PrintDate "Alexandrian", year, month, day
 
ComputusGetGregorian year, month, day
PrintDate "Gregorian", year, month, day
 
' Для Visual Basic добавить здесь End Sub
</syntaxhighlight>
 
===[[w:C|C]]===
<syntaxhighlight lang="c">
/* computus.h */
 
#ifndef _COMPUTUS_H_
#define _COMPUTUS_H_
 
 
typedef unsigned short Year;
typedef unsigned char Month;
typedef unsigned char Day;
 
/*
computus_get_alexandrian вычисляет для данного года месяц и день православной Пасхи (юлианская дата).
*/
void computus_get_alexandrian(Year year, Month *month, Day *day);
 
/*
computus_get_gregorian вычисляет для данного года месяц и день католической Пасхи (григорианская дата).
*/
void computus_get_gregorian(Year year, Month *month, Day *day);
 
 
#endif
 
 
/* computus.c */
 
#include "computus.h"
 
 
/*
_computus_get_easter вычисляет по данному фактору месяц и день Пасхи (приватная функция).
*/
void _computus_get_easter(Year factor, Month *month, Day *day) {
*month = Month(factor / 31);
*day = Day(factor % 31 + 1);
}
 
void computus_get_alexandrian(Year year, Month *month, Day *day) {
Year d = (year % 19 * 19 + 15) % 30;
_computus_get_easter(d + (year % 4 * 2 + year % 7 * 4 + 34 - d) % 7 + 114, month, day);
}
 
void computus_get_gregorian(Year year, Month *month, Day *day) {
Year
a = year % 19,
b = year / 100,
c = year % 100,
h = (19 * a + b - b / 4 - (b - (b + 8) / 25 + 1) / 3 + 15) % 30,
l = (32 + (b % 4 + c / 4) * 2 - h - c % 4) % 7;
_computus_get_easter(h + l - (11 * (h + l + l) + a) / 451 * 7 + 114, month, day);
}
</syntaxhighlight>
Пример использования:
<syntaxhighlight lang="c">
/* computus_test.c */
 
#include <stdio.h>
 
#include "computus.h"
 
 
/*
print_date выводит дату в формате:
К: ГГГГ-ММ-ДД
где К — название календаря, ГГГГ — год, ММ — двузначный номер месяца, ДД — двузначное число.
*/
void print_date(const char *calendar, Year year, Month month, Day day) {
printf("%s: %hu-%.2hu-%.2hu\n", calendar, year, month, day);
}
 
int main() {
Year year;
printf("Year? ");
scanf("%hu", &year);
 
Month month;
Day day;
 
computus_get_alexandrian(year, &month, &day);
print_date("Alexandrian", year, month, day);
 
computus_get_gregorian(year, &month, &day);
print_date("Gregorian", year, month, day);
}
</syntaxhighlight>
 
===[[w:C++|C++]]===
<syntaxhighlight lang="cpp">
// computus.hpp
 
#pragma once
 
 
namespace computus {
 
typedef unsigned short Year;
typedef unsigned char Month;
typedef unsigned char Day;
 
// getAlexandrian вычисляет для данного года месяц и день православной Пасхи (юлианская дата).
void getAlexandrian(Year year, Month &month, Day &day);
 
// getGregorian вычисляет для данного года месяц и день католической Пасхи (григорианская дата).
void getGregorian(Year year, Month &month, Day &day);
 
}
 
 
// computus.cpp
 
#include "computus.hpp"
 
 
namespace computus {
 
// _getEaster вычисляет по данному фактору месяц и день Пасхи (приватная функция).
void _getEaster(Year factor, Month &month, Day &day) {
month = Month(factor / 31);
day = Day(factor % 31 + 1);
}
 
void getAlexandrian(Year year, Month &month, Day &day) {
Year d = (year % 19 * 19 + 15) % 30;
_getEaster(d + (year % 4 * 2 + year % 7 * 4 + 34 - d) % 7 + 114, month, day);
}
void getGregorian(Year year, Month &month, Day &day) {
Year
a = year % 19,
b = year / 100,
c = year % 100,
h = (19 * a + b - b / 4 - (b - (b + 8) / 25 + 1) / 3 + 15) % 30,
l = (32 + (b % 4 + c / 4) * 2 - h - c % 4) % 7;
_getEaster(h + l - (11 * (h + l + l) + a) / 451 * 7 + 114, month, day);
}
 
}
</syntaxhighlight>
Пример использования:
<syntaxhighlight lang="cpp">
// computus_test.cpp
 
#include <iostream>
#include <iomanip>
 
#include "computus.hpp"
 
 
// printDate выводит дату в формате:
// К: ГГГГ-ММ-ДД
// где К — название календаря, ГГГГ — год, ММ — двузначный номер месяца, ДД — двузначное число.
void printDate(const char *calendar, computus::Year year, computus::Month month, computus::Day day) {
std::cout
<< calendar << ':' << ' ' << year
<< '-' << std::setw(2) << std::setfill('0') << int(month)
<< '-' << std::setw(2) << std::setfill('0') << int(day)
<< '\n';
}
 
int main() {
computus::Year year;
std::cout << "Year? ";
std::cin >> year;
 
computus::Month month;
computus::Day day;
 
computus::getAlexandrian(year, month, day);
printDate("Alexandrian", year, month, day);
 
computus::getGregorian(year, month, day);
printDate("Gregorian", year, month, day);
}
</syntaxhighlight>
 
== =[[w:Excel|Excel]] ===
=DOLLAR(("4/"&A1)/7+MOD(19*MOD(A1,19)-7,30)*14%,)*7-6
: Предполагается, что ячейка A1 содержит год.<ref>{{cite web|last=Walkenbach|first=John|title=Calculating Easter|url=http://spreadsheetpage.com/index.php/tip/calculating_easter/|archiveurl=http://www.webcitation.org/6FcDT117e|archivedate=2013-04-04}}</ref> Формула вычисляет дату католической Пасхи и даетдаёт верный результат для 1900—2203 1900…2203 годов.
 
== =[[w:PythonGo|PythonGo]] ===
<syntaxhighlight lang="go">
// computus.go
 
package computus
 
type Year = uint16
type Month = uint8
type Day = uint8
 
// easter вычисляет по данному фактору месяц и день Пасхи (приватная функция).
func easter(factor Year) (Month, Day) {
return Month(factor / 31), Day(factor % 31 + 1)
}
 
// Alexandrian вычисляет для данного года месяц и день православной Пасхи (юлианская дата).
func Alexandrian(year Year) (Month, Day) {
d := (year % 19 * 19 + 15) % 30
return easter(d + (year % 4 * 2 + year % 7 * 4 + 34 - d) % 7 + 114)
}
 
// Gregorian вычисляет для данного года месяц и день католической Пасхи (григорианская дата).
func Gregorian(year Year) (Month, Day) {
a := year % 19
b := year / 100
c := year % 100
h := (19 * a + b - b / 4 - (b - (b + 8) / 25 + 1) / 3 + 15) % 30
l := (32 + (b % 4 + c / 4) * 2 - h - c % 4) % 7
return easter(h + l - (11 * (h + l + l) + a) / 451 * 7 + 114)
}
</syntaxhighlight>
Пример использования:
<syntaxhighlight lang="go">
// computus_test.go
 
package main
 
import (
"computus"
"fmt"
)
 
// printDate выводит дату в формате:
// К: ГГГГ-ММ-ДД
// где К — название календаря, ГГГГ — год, ММ — двузначный номер месяца, ДД — двузначное число.
func printDate(calendar string, year Year, month Month, day Day) {
fmt.Printf("%s: %d-%02d-%02d\n", calendar, year, month, day)
}
 
func main() {
var year computus.Year
print("Year? ")
fmt.Scanln(&year)
 
var month computus.Month
var day computus.Day
 
month, day = computus.Alexandrian(year)
printDate("Alexandrian", year, month, day)
 
month, day = computus.Gregorian(year)
printDate("Gregorian", year, month, day)
}
</syntaxhighlight>
 
===[[w:Pascal|Pascal]], [[w:Delphi|Delphi]]===
<syntaxhighlight lang="pascal">
{ computus.pas }
 
UNIT Computus;
 
INTERFACE
 
TYPE
TYear = Word;
TMonth = 1..12;
TDay = 1..31;
 
{
GetAlexandrian вычисляет для данного года месяц и день православной Пасхи (юлианская дата).
}
procedure GetAlexandrian(year: TYear; var month: TMonth; var day: TDay);
 
{
GetGregorian вычисляет для данного года месяц и день католической Пасхи (григорианская дата).
}
procedure GetGregorian(year: TYear; var month: TMonth; var day: TDay);
 
IMPLEMENTATION
 
{
_Easter вычисляет по данному фактору месяц и день Пасхи (приватная функция).
}
procedure _GetEaster(factor: TYear; var month: TMonth; var day: TDay);
begin
month := factor div 31;
day := factor mod 31 + 1
end;
 
procedure GetAlexandrian(year: TYear; var month: TMonth; var day: TDay);
var d: TYear;
begin
d := (year mod 19 * 19 + 15) mod 30;
_GetEaster(d + (year mod 4 * 2 + year mod 7 * 4 + 34 - d) mod 7 + 114, month, day)
end;
 
procedure GetGregorian(year: TYear; var month: TMonth; var day: TDay);
var a, b, c, h, l: TYear;
begin
a := year mod 19;
b := year div 100;
c := year mod 100;
h := (19 * a + b - b div 4 - (b - (b + 8) div 25 + 1) div 3 + 15) mod 30;
l := (32 + (b mod 4 + c div 4) * 2 - h - c mod 4) mod 7;
_GetEaster(h + l - (11 * (h + l + l) + a) div 451 * 7 + 114, month, day)
end;
 
END.
</syntaxhighlight>
Пример использования:
<syntaxhighlight lang="pascal">
{ computus_test.pas }
 
PROGRAM ComputusTest;
 
USES Computus;
 
VAR year: Computus.TYear;
month: Computus.TMonth;
day: Computus.TDay;
 
{
PrintDate выводит дату в формате:
К: ГГГГ-ММ-ДД
где К — название календаря, ГГГГ — год, ММ — двузначный номер месяца, ДД — двузначное число.
}
procedure PrintDate(calendar: String; year: TYear; month: TMonth; day: TDay);
begin
Write(calendar, ': ', year, '-');
if month < 10 then
Write('0');
Write(month, '-');
if day < 10 then
Write('0');
WriteLn(day)
end;
 
BEGIN
Write('Year? ');
ReadLn(year);
 
Computus.GetAlexandrian(year, month, day);
PrintDate('Alexandrian', year, month, day);
 
Computus.GetGregorian(year, month, day);
PrintDate('Gregorian', year, month, day)
END.
</syntaxhighlight>
 
===[[w:Perl|Perl]]===
: Rich Bowen’s модуль ''Date::Easter'' доступен на сайте CPAN .<ref>{{cite web|title=Date::Easter|url=http://search.cpan.org/~rbow/Date-Easter-1.14/lib/Date/Easter.pm|publisher=CPAN|archiveurl=http://www.webcitation.org/6FcDSMkSb|archivedate=2013-04-04}}</ref>
 
===[[w:Python|Python]]===
<syntaxhighlight lang="python">
# computus.py
def IanTaylorEasterJscr(year):
 
def _easter(factor):
"""
_easter вычисляет по данному фактору месяц и день Пасхи (приватная функция).
"""
return factor // 31, factor % 31 + 1
 
def alexandrian(year):
"""
alexandrian вычисляет для данного года месяц и день православной Пасхи (юлианская дата).
"""
d = (year % 19 * 19 + 15) % 30
return _easter(d + (year % 4 * 2 + year % 7 * 4 + 34 - d) % 7 + 114)
 
def gregorian(year):
"""
gregorian вычисляет для данного года месяц и день католической Пасхи (григорианская дата).
"""
a = year % 19
b = year >>// 2100
c = byear //% 25 + 1100
dh = (c19 * a + b - b // 4 - (b - (b + 8) // 25 + 1) // 3 + 15) >>% 230
el = ((a32 * 19) -+ ((cb *% 84 + 5)c // 254) +* d2 +- h - c % 154) % 307
ereturn _easter(h += (29578l - (11 * (h + l + l) + a) -// e451 * 32)7 >>+ 10114)
</syntaxhighlight>
e -= ((year % 7) + b - d + e + 2) % 7
Пример использования:
d = e >> 5
<syntaxhighlight lang="python">
day = e - d * 31
# computus_test.py
month = d + 3
return year, month, day
</syntaxhighlight><br />
 
import computus
== [[w:C++|C++]] ==
<syntaxhighlight lang="cpp">
class Date
{
public:
int day;
int month;
int year;
};
 
// возвращает дату григорианского календаря
// по книге Jean Meeus Astronomical Algorithms
Date CatholicEaster( int year )
{
Date easterDate;
 
def print_date(calendar, year, month, day):
int a = year % 19;
"""
int b = year / 100;
print_date выводит дату в формате:
int c = year % 100;
К: ГГГГ-ММ-ДД
int d = b / 4;
где К — название календаря, ГГГГ — год, ММ — двузначный номер месяца, ДД — двузначное число.
int e = b % 4;
"""
int f = (b + 8) / 25;
print("%s: %d-%02d-%02d" % (calendar, year, month, day))
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;
int month = (h + l - 7 * m + 114) / 31;
int day = ((h + l - 7 * m + 114) % 31) + 1;
 
year = int(input("Year? "))
easterDate.day = day;
easterDate.month = month;
easterDate.year = year;
 
month, day = computus.alexandrian(year)
return easterDate;
print_date("Alexandrian", year, month, day)
 
month, day = computus.gregorian(year)
print_date("Gregorian", year, month, day)
</syntaxhighlight>
 
===[[w:Rust|Rust]]===
<syntaxhighlight lang="rust">
// computus.rs
 
type Year = u16;
type Month = u8;
type Day = u8;
 
// easter вычисляет по данному фактору месяц и день Пасхи (приватная функция).
fn _easter(factor: Year) -> (Month, Day) {
((factor / 31) as Month, (factor % 31 + 1) as Day)
}
 
// Alexandrian вычисляет для данного года месяц и день православной Пасхи (юлианская дата).
// возвращает дату юлианского календаря
pub fn alexandrian(year: Year) -> (Month, Day) {
// по книге Jean Meeus Astronomical Algorithms
let d = (year % 19 * 19 + 15) % 30;
Date OrthodoxEaster( int year )
_easter(d + (year % 4 * 2 + year % 7 * 4 + 34 - d) % 7 + 114)
{
}
Date easterDate;
 
// Gregorian вычисляет для данного года месяц и день католической Пасхи (григорианская дата).
int a = year % 4;
pub fn gregorian(year: Year) -> (Month, Day) {
int b = year % 7;
intlet ca = year % 19;
intlet db = (19year */ c + 15) % 30100;
intlet ec = (2 * a + 4 * b - d + 34)year % 7100;
intlet monthh = (d19 * a + eb - b / 4 - (b - (b + 1148) / 3125 + 1) / 3 + 15) % 30;
intlet dayl = ((d32 + e(b % 4 + 114c / 4) * 2 - h - c % 314) +% 17;
_easter(h + l - (11 * (h + l + l) + a) / 451 * 7 + 114)
}
</syntaxhighlight>
Пример использования:
<syntaxhighlight lang="rust">
// computus_test.rs
 
mod computus;
 
// read_var считывает данные из стандартного потока ввода.
fn read_var<Type: std::str::FromStr>(var: &mut Type) -> bool {
let mut input_text = String::new();
std::io::stdin()
.read_line(&mut input_text)
.expect("Unable to read from standard input.");
match input_text.trim().parse::<Type>() {
Ok(value) => {
*var = value;
true
}
Err(..) => false,
}
}
 
// print_date выводит дату в формате:
// К: ГГГГ-ММ-ДД
// где К — название календаря, ГГГГ — год, ММ — двузначный номер месяца, ДД — двузначное число.
fn print_date(calendar: &str, year: computus::Year, (month, day): (computus::Month, computus::Day)) {
println!("{}: {}-{:02}-{:02}", calendar, year, month, day);
}
 
fn main() {
easterDate.day = day;
let mut year: computus::Year;
easterDate.month = month;
easterDate.year = year;
 
returnprint!("Year? easterDate");
if read_var(&mut year) {
print_date("Alexandrian", year, alexandrian(year));
print_date("Gregorian", year, gregorian(year));
}
}
</syntaxhighlight>
74

правки