الگوریتم گاهشماری ایرانی برای نرم‌افزارهای مبدل تقویم‌ها

در روزهای اخیر چند پرسش در زمینه ساختار محاسباتی بکارگرفته شده در الگوریتم‌های متداول نرم‌افزارهای تبدیل‌کننده تقویم‌ها (Calendar converter) برای گاهشماری ایرانی و نیز دقیق‌ترین و کارآمدترین نرم‌افزارهای موجود برای تبدیل تقویم ایرانی به دیگر تقویم‌ها به نگارنده رسیده است که اکنون به پاسخ کوتاهی بسنده می‌شود تا در آینده با تفصیل بیشتری به این نکته مهم پرداخته شود.

اکنون نرم‌افزارهای گوناگونی برای تبدیل متقابل تقویم ایرانی (هجری خورشیدی/ هجری شمسی) به دیگر تقویم‌ها وجود دارد که هر یک از آنها محاسن و معایبی در قیاس با یکدیگر دارند. مهم‌ترین کمبود بیشتر نرم‌افزارها، بهره‌گیری از الگوریتم‌هایی با دامنه خطای بالا و کم‌کارآمد، دامنه کوتاه مدت سال‌های تطبیق‌پذیر و بسنده‌کردن به تبدیل تقویم ایرانی با تقویم میلادی گریگوری است.

مناسب‌ترین و کارا‌ترین الگوریتم برای نظام کبیسه‌گیری و نیز تبدیل گاهشماری ایرانی، الگوریتمی است که متکی به ۶۸۳ روز افزوده برای ۶۸۳ سال کبیسه با قواعد خاص توزیعی خود در یک دوره بزرگ ۲۸۲۰ ساله باشد. در این صورت، طول متوسط سال تعریف‌شده یا طول سال تقویمی ایرانی برابر است با ۲۴۲۱۹۹/۳۶۵ روز یا ۳۶۵ روز و ۵ ساعت و ۴۸ دقیقه و ۴۶ ثانیه. دامنه خطای عملی در مقایسه با تعریف‌های بنیادین این نظام برابر است با ۰۰۰۰۰۰۴۱۸۴۴/۰ روز یا ۰۳۶/۰ ثانیه در سال و یا یک ثانیه در هر ۲۸ سال و ۱۰۲ ثانیه در هر دوره ۲۸۲۰ ساله. (این دقت در گاهشماری میلادی گریگوری ۴۳/۴ ثانیه و در گاهشماری میلادی ژولی ۶۷۵ ثانیه در سال است.)

به کارگیری قواعد محاسباتی دوره ۲۸۲۰ ساله و دستگاه توزیع روزهای افزوده در ۶۸۳ سال کبیسه‌ مفروض آن، منجر به ایجاد کارآمدترین نظام ممکن برای تبدیل تقویم‌ها (Calendar converter) و به ویژه در قیاس با تقویم طبیعی خواهد شد.

الگوریتم زیر یکی از بهترین نمونه‌ها بر اساس دوره ۲۸۲۰ ساله است که در بسیاری از برنامه‌های تبدیلی تقویم‌های جهان بکار می‌رود. این الگوریتم را به تازگی آقای مارک جیسون دومینوس (Mark Jason Dominus) به زبان برنامه‌نویسی «پرل» (Perl) نیز نوشته که در پایان همین صفحه آمده است. آقای جان واکر John Walker نیز در سال ۲۰۰۶ گونه توسعه یافته این الگوریتم را در برنامه قدرتمند Formilab بکار گرفته و نیز در Calendar Home از آن اقتباس شده است.

نگارنده این دو برنامه را که از الگوریتم یکسانی بهره گرفته‌اند، برای دویست سال گوناگون در یک دامنه پنج‌هزار ساله که از ترکیب‌های کبیسه‌ متنوعی برخوردار بوده‌اند، آزمایش کرده و به نتیجه نادرستی برخورد نکرده است. این آزمایش برای تبدیل تقویم ایرانی و بالعکس به میلادی ژولی، میلادی گریگوری، هجری قمری، عبرانی (بازمانده گاهشماری رسمی شاهنشاهی هخامنشی) و روز ژولی انجام شد.

یادآور می‌شود که برای داده‌های تاریخی که نتیجه تبدیل آنها به تقویم میلادی یا برعکس، سال‌های پیش از ۱۵۸۲ میلادی باشد، می‌باید به دستگاه میلادی ژولی (و نه میلادی گریگوری) رجوع کرد. همچنین برای برخی داده‌های تاریخی پس از سال ۱۵۸۲ نیز می‌باید به تقویم میلادی ژولی مراجعه کرد. چرا که تقویم گریگوری در زمانی یکسان در همه کشورها پذیرفته نشده و رویدادهای تاریخی در آن کشورها گاه تا چند سده بعد همچنان به تقویم میلادی ژولی ثبت شده‌اند. این دو نکته، از خطاهای متداول در تبدیل تقویم‌ها است. خطای متداول دیگر، بی‌توجهی به وجود سال صفر در گاهشماری میلادی گریگوری است. چنانچه کاربر به هر دلیلی قصد داشته باشد رویداد خاصی را با تعمیم تقویم میلادی گریگوری به گذشته به دست آورد، می‌باید این نکته را در نظر داشت که این گاهشماری دارای سال صفر تعریف‌شده (برابر با سال ۱- ژولی) است. به عبارت دیگر برای سال‌های پیش از مبدأ میلادی، تفاوتی یک ساله در سالشماری میلادی گریگوری و ژولی وجود دارد.

۱٫ Let a = (y + 2345) % 2820

۲٫ If a is 2819, y is a leap year. Otherwise,

۳٫ Let b = a % 128.

۴٫ If b < 29, let c = b. Otherwise, let c = (b – ۲۹) % ۳۳٫

۵٫ If c = 0, y is not a leap year. Otherwise,

۶٫ If c is a multiple of 4, y is a leap year. Otherwise,

۷٫ y is not leap year.

——————————

#!/usr/bin/perl

# is Persian year y a leap year in the Persian calendar?

sub is_leap_year {

my $y = shift;

my $a = ($y + 2345) % 2820;

return 1 if $a == 2819;

my $b = $a % 128;

my $c;

if ($b < 29) { $c = $b }

else { $c = ($b – ۲۹) % ۳۳ }

return 0 if $c == 0;

return 1 if $c %4 == 0;

return 0;

}

# Is Gregorian year g a leap year ** in the Persian calendar **?

sub is_gregorian_leap_year {

my $g = shift;

return is_leap_year($g – ۲۰۰۸ + ۱۳۸۶);

}

my $prev;

for (1979 .. 2028) {

my $is = is_g_leap_year($_);

printf “%۴d %s\n”, $_, $is ? “*” : ” “;

die if $is && $prev;

$prev = $is;

# $ct++ if $is;

}

#print “>> $ct\n”;

  • 0

    Overall Score

  • ‎رتبه‌بندی خوانندگان‫:‬0 Votes

هم‌رسانی

احتمالا به این‌ها نیز علاقه‌مندید:

دیدگاه شما چیست؟

Your email address will not be published. Required fields are marked *