نمایش نتایج 1 تا 4 از 4

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

  1. #1

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

    اکنون نرم‌افزارهای گوناگونی برای تبدیل متقابل تقویم ایرانی (هجری خورشیدی/ هجری شمسی) به دیگر تقویم‌ها وجود دارد که هر یک از آنها محاسن و معایبی در قیاس با یکدیگر دارند. مهم‌ترین کمبود بیشتر نرم‌افزارها، بهره‌گیری از الگوریتم‌هایی با دامنه خطای بالا و کم‌کارآمد، دامنه کوتاه مدت سال‌های تطبیق‌پذیر و بسنده‌کردن به تبدیل تقویم ایرانی با تقویم میلادی گریگوری است.
    مناسب‌ترین و کارا‌ترین الگوریتم برای نظام کبیسه‌گیری و نیز تبدیل گاهشماری ایرانی، الگوریتمی است که متکی به ۶۸۳ روز افزوده برای ۶۸۳ سال کبیسه با قواعد خاص توزیعی خود در یک دوره بزرگ ۲۸۲۰ ساله باشد. در این صورت، طول متوسط سال تعریف‌شده یا طول سال تقویمی ایرانی برابر است با ۲۴۲۱۹۹/۳۶۵ روز یا ۳۶۵ روز و ۵ ساعت و ۴۸ دقیقه و ۴۶ ثانیه. دامنه خطای عملی در مقایسه با تعریف‌های بنیادین این نظام برابر است با ۰۰۰۰۰۰۴۱۸۴۴/۰ روز یا ۰۳۶/۰ ثانیه در سال و یا یک ثانیه در هر ۲۸ سال و ۱۰۲ ثانیه در هر دوره ۲۸۲۰ ساله. (این دقت در گاهشماری میلادی گریگوری ۴۳/۴ ثانیه و در گاهشماری میلادی ژولی ۶۷۵ ثانیه در سال است.)
    بکارگیری قواعد محاسباتی دوره ۲۸۲۰ ساله و دستگاه توزیع روزهای افزوده در ۶۸۳ سال کبیسه‌ مفروض آن، منجر به ایجاد کارآمدترین نظام ممکن برای تبدیل تقویم‌ها (Calendar converter) و به ویژه در قیاس با تقویم طبیعی خواهد شد.
    الگوریتم زیر یکی از بهترین نمونه‌ها بر اساس دوره ۲۸۲۰ ساله است که در بسیاری از برنامه‌های تبدیلی تقویم‌های جهان بکار می‌رود. این الگوریتم را به تازگی آقای مارک جیسون دومینوس (Mark Jason Dominus) به زبان برنامه‌نویسی «پرل» (Perl) نیز نوشته که در پایان همین صفحه آمده است. آقای جان واکر John Walker نیز در سال ۲۰۰۶ گونه توسعه یافته این الگوریتم را در برنامه قدرتمند Formilab بکار گرفته و نیز در Calendar Home از آن اقتباس شده است. برای استفاده عملی از این الگوریتم به نرم‌افزار تبدیل تقویم‌ها مراجعه کنید.
    نگارنده این دو برنامه را که از الگوریتم یکسانی بهره گرفته‌اند، برای دویست سال گوناگون در یک دامنه پنج‌هزار ساله که از ترکیب‌های کبیسه‌ متنوعی برخوردار بوده‌اند، آزمایش کرده و به نتیجه نادرستی برخورد نکرده است. این آزمایش برای تبدیل تقویم ایرانی و بالعکس به میلادی ژولی، میلادی گریگوری، هجری قمری، عبرانی (بازمانده گاهشماری رسمی شاهنشاهی هخامنشی) و روز ژولی انجام شد.
    یادآور می‌شود که برای داده‌های تاریخی که نتیجه تبدیل آنها به تقویم میلادی یا برعکس، سال‌های پیش از ۱۵۸۲ میلادی باشد، می‌باید به دستگاه میلادی ژولی (و نه میلادی گریگوری) رجوع کرد. همچنین برای برخی داده‌های تاریخی پس از سال ۱۵۸۲ نیز می‌باید به تقویم میلادی ژولی مراجعه کرد. چرا که تقویم گریگوری در زمانی یکسان در همه کشورها پذیرفته نشده و رویدادهای تاریخی در آن کشورها گاه تا چند سده بعد همچنان به تقویم میلادی ژولی ثبت شده‌اند. این دو نکته، از خطاهای متداول در تبدیل تقویم‌ها است. خطای متداول دیگر، بی‌توجهی به وجود سال صفر در گاهشماری میلادی گریگوری است. چنانچه کاربر به هر دلیلی قصد داشته باشد رویداد خاصی را با تعمیم تقویم میلادی گریگوری به گذشته به دست آورد، می‌باید این نکته را در نظر داشت که این گاهشماری دارای سال صفر تعریف‌شده (برابر با سال ۱- ژولی) است. به عبارت دیگر برای سال‌های پیش از مبدأ میلادی، تفاوتی یک ساله در سالشماری میلادی گریگوری و ژولی وجود دارد.
    1. Let a = (y + 2345) % 2820
    2. If a is 2819, y is a leap year. Otherwise,
    3. Let b = a % 128.
    4. If b < 29, let c = b. Otherwise, let c = (b – 29) % 33.
    5. If c = 0, y is not a leap year. Otherwise,
    6. If c is a multiple of 4, y is a leap year. Otherwise,
    7. 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 – 29) % 33 }
    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 – 2008 + 1386);
    }

    my $prev;
    for (1979 .. 2028) {
    my $is = is_g_leap_year($_);
    printf “%4d %s\n”, $_, $is ? “*” : ” “;
    die if $is && $prev;
    $prev = $is;
    # $ct++ if $is;
    }
    #print “>> $ct\n”;


    رضا مرادی غیاث آبادی
    جمعه ۲۴ اسفند ۱۳۸۶
    http://ghiasabadi.com/algorithm.html

  2. #2
    کاربر دائمی آواتار FastCode
    تاریخ عضویت
    تیر 1388
    محل زندگی
    /dev/null
    پست
    3,486

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

    سلام.
    خیلی جالب بود.
    اگر ممکنه ویکیپدیای فارسی رو هم ویرایش کنید.ممکنه بعداً این صفحه رو دیگه پیدا نکنم.

    مرسی.

  3. #3

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

    نقل قول نوشته شده توسط FastCode مشاهده تاپیک
    سلام.
    خیلی جالب بود.
    اگر ممکنه ویکیپدیای فارسی رو هم ویرایش کنید.ممکنه بعداً این صفحه رو دیگه پیدا نکنم.

    مرسی.
    منم اتفاقی این صفحه رو پیدا کردم برای اینکه گمش نکنم و برای روز مبدا گذاشتم اینجا ، چشم سعی می کنم به ویکیپیدیا هم انتقال بدم.

  4. #4

    الگوريتم تبديل تاريخ ميلادي به تاريخ شمسي

    تبديل تاريخ ميلادي به شمسي بسيار راحتتر از تبديل تاريخ شمسي به ميلادي است. براي نوشتن اين الگوريتم به اختلاف روزهاي ميان اولين روز سال ميلادي و اولين روز سال شمسي نياز داريم که اين اختلاف روز (در صورتي که سال کبيسه باشد يا نباشد) "79" روز است. براي تشخيص کبيسه بودن يا نبودن سال از روش زير استفاده مي کنيم:
    "اگر سال داده شده بر100و 400 بخشپذير باشد" يا بر" 100 بخشپذير نباشد بر 4 بخشپذير باشد" آنگاه سال کبيسه است، در غير اين صورت سال کبيسه نيست.با توجه به کبيسه بودن يا کبيسه نبودن سال مشخص مي کنيم که در کدامين روز سال ميلادي قرار داريم.دو حالت پيش مي آيد:

    • روزي که در آن قرار داريم از 79 بيشتر است
    به اين معني است که در ماههاي بعد از فروردين قرار داريم.حال بايد مشخص کنيم که در 6 ماه اول سال شمسي قرار داريم يا در 6 ماه دوم سال قرار داريم،براي اينکار ابتدا 79 روز از تعداد روزها کم مي کنيم تا در اول فروردين قرار بگيريم حال اگر تعداد روزها از "186" (31*6) کمتر باشد يعني در 6 ماه اول سال شمسي قرار داريم در غير اينصورت در 6 ماه دوم قرار داريم.

    1. اگر در 6 ماه اول سال قرار گرفته باشيم :تعداد روزها را بر "31" تقسيم مي کنيم (6 ماه اول در سال شمسي 31 روزه است.)اگر باقيمانده اين تقسيم صفر شد خارج قسمت تقسيم برابر با ماه شمسي مي شود و روز شمسي برابر با 31 مي شود.اگر باقيمانده صفر نشود ماه شمسي برابر با خارج قسمت باضافه يک مي شود و روز شمسي همان باقيمانده است.

    2. اگر در 6 ماه دوم سالقرار گرفته باشيم : "186" روز از تعداد روزها کم مي کنيم و آن را بر "30" تقسيم مي کنيم .اگرباقيمانده اين تقسيم صفر شد خارج قسمت تقسيم باضافه"6" برابر با ماه شمسي مي شودو روز شمسي برابر با30 مي شود.اگر باقيمانده صفر نشود ماه شمسي برابر با خارج قسمت باضافه "7" مي شود و روز شمسي همان باقيمانده است. سال شمسي از تفاضل سال ميلادي با "621" بدست مي آيد.

    • روزي که در آن قرار داريم کمتر از "79" است :
    که اين به اين معني است که درروزهايي بين اولين روزسال ميلادي تا اولين روز شمسي (ماههاي دي ،بهمن و اسفند)قرار داريم.اختلاف روز بين اولين روز سال ميلادي داده شده و اولين روز دي ماه در سال شمسي را در نظر مي گيريم که اين اختلاف براي سال کبيسه"11" و براي غير کبيسه "10" است.*دقت کنيد که در اين الگوريتم براي مشخص کردن اين اختلاف بايد سال قبل از سال داده شده را در نظر بگيريم زيرا سال قبل بر روي اولين روز سال ميلادي تاثير مي گزارد.*
    اختلاف روز با تعداد روز محاسبه شده جمع مي کنيم ، آن را بر"30" تقسيم مي کنيم(3 ماه آخر سال شمسي 30 روزه است.).
    اگر باقيمانده اين تقسيم صفر شود خارج قسمت تقسيم باضافه"9" برابر با ماه شمسي مي شودو روز شمسي برابر با "30" مي شود.اگر باقيمانده صفر نشود ماه شمسي برابر با خارج قسمت باضافه"10"مي شودو روز شمسي همان باقيمانده است.در اين حالت سال شمسي از تفاضل سال ميلادي با"622" بدست مي آيد.(زيرا در سال قبل قرار داريم.)


    کد کامل تبدیل تاریخ میلادی به شمسی:


    Function MiladiToShamsi(var Year, Month, Day: Word): String;
    const
    count_days : array[1..12] of Byte = (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
    var
    i: Byte;
    st: String;
    day_year: Integer;
    begin
    day_year:= 0;
    for i:= 1 to month - 1 do
    day_year:= day_year + count_days[i];
    day_year:= day_year + day;

    if IsLeapYear(Year) and (month > 2) then
    Inc(day_year);

    if (day_year <= 79) then
    begin
    if ((Year - 1) mod 4 = 0) then
    day_year:= day_year + 11
    else
    day_year:= day_year + 10;

    Year:= Year - 622;

    if (day_year mod 30 = 0) then
    begin
    Month:= (day_year div 30) + 9;
    Day:= 30;
    end
    else
    begin
    Month:= (day_year div 30) + 10;
    Day:= day_year mod 30;
    end;
    end
    else
    begin
    year:= year - 621;

    day_year:= day_year - 79;
    if (day_year <= 186) then
    begin
    if (day_year mod 31 = 0) then
    begin
    Month:= (day_year div 31);
    Day:= 31;
    end
    else
    begin
    Month:= (day_year div 31) + 1;
    Day:= day_year mod 31;
    end;
    end
    else
    begin
    day_year:= day_year - 186;
    if (day_year mod 30 = 0) then
    begin
    Month:= (day_year div 30) + 6;
    Day:= 30;
    end
    else
    begin
    Month:= (day_year div 30) + 7;
    Day:= day_year mod 30;
    end;
    end;
    end; // else .

    st:= IntToStr(Year) + '/';
    if (Month < 10) then
    st:= st + '0';
    st:= st + IntToStr(Month) + '/';
    if (Day < 10) then
    st:= st + '0';
    st:= st + IntToStr(Day);

    Result:= st;
    end;


    منبع : http://ebrahimkhodaei.blogfa.com/post-18.aspx

قوانین ایجاد تاپیک در تالار

  • شما نمی توانید تاپیک جدید ایجاد کنید
  • شما نمی توانید به تاپیک ها پاسخ دهید
  • شما نمی توانید ضمیمه ارسال کنید
  • شما نمی توانید پاسخ هایتان را ویرایش کنید
  •