سؤال

ما هو التنفيذ الجيد لوظيفة IsLeapYear في VBA؟

يحرر: لقد قمت بتشغيل تنفيذ if-then وDateSerial مع تكرارات ملفوفة في جهاز توقيت، وكان DateSerial أسرع في المتوسط ​​بمقدار 1-2 مللي ثانية (5 عمليات تشغيل من 300 تكرار، مع صيغة ورقة عمل خلية واحدة متوسطة تعمل أيضًا).

هل كانت مفيدة؟

المحلول

Public Function isLeapYear(Yr As Integer) As Boolean  

    ' returns FALSE if not Leap Year, TRUE if Leap Year  

    isLeapYear = (Month(DateSerial(Yr, 2, 29)) = 2)  

End Function  

لقد حصلت في الأصل على هذه الوظيفة من موقع Excel الرائع الخاص بـ Chip Pearson.

موقع بيرسون

نصائح أخرى

public function isLeapYear (yr as integer) as boolean
    isLeapYear   = false
    if (mod(yr,400)) = 0 then isLeapYear  = true
    elseif (mod(yr,100)) = 0 then isLeapYear  = false
    elseif (mod(yr,4)) = 0 then isLeapYear  = true
end function

ويكيبيديا للمزيد...http://en.wikipedia.org/wiki/Leap_year

إذا كانت الكفاءة أحد الاعتبارات وكانت السنة المتوقعة عشوائية، فقد يكون من الأفضل قليلاً القيام بالحالة الأكثر شيوعًا أولاً:

public function isLeapYear (yr as integer) as boolean
    if (mod(yr,4)) <> 0 then isLeapYear  = false
    elseif (mod(yr,400)) = 0 then isLeapYear  = true
    elseif (mod(yr,100)) = 0 then isLeapYear  = false
    else isLeapYear = true
end function

كبديل لحل Chip Pearson، يمكنك أيضًا تجربته

Public Function isLeapYear(Yr As Integer) As Boolean  

  ' returns FALSE if not Leap Year, TRUE if Leap Year  

  isLeapYear = (DAY(DateSerial(Yr, 3, 0)) = 29)  

End Function

لقد وجدت هذا واحد مضحك على CodeToad :

Public Function IsLeapYear(Year As Varient) As Boolean
  IsLeapYear = IsDate("29-Feb-" & Year)
End Function 

على الرغم من أنني متأكد تمامًا من أن استخدام IsDate في إحدى الوظائف ربما يكون أبطأ من اثنين من if وelseifs.

Public Function ISLeapYear(Y As Integer) AS Boolean
 ' Uses a 2 or 4 digit year
'To determine whether a year is a leap year, follow these steps:
'1    If the year is evenly divisible by 4, go to step 2. Otherwise, go to step 5.
'2    If the year is evenly divisible by 100, go to step 3. Otherwise, go to step 4.
'3    If the year is evenly divisible by 400, go to step 4. Otherwise, go to step 5.
'4    The year is a leap year (it has 366 days).
'5    The year is not a leap year (it has 365 days).

If Y Mod 4 = 0 Then ' This is Step 1 either goto step 2 else step 5
    If Y Mod 100 = 0 Then ' This is Step 2 either goto step 3 else step 4
        If Y Mod 400 = 0 Then ' This is Step 3 either goto step 4 else step 5
            ISLeapYear = True ' This is Step 4 from step 3
                Exit Function
        Else: ISLeapYear = False ' This is Step 5 from step 3
                Exit Function
        End If
    Else: ISLeapYear = True ' This is Step 4 from Step 2
            Exit Function
    End If
Else: ISLeapYear = False ' This is Step 5 from Step 1
End If


End Function
Public Function isLeapYear(Optional intYear As Variant) As Boolean

    If IsMissing(intYear) Then
        intYear = Year(Date)
    End If

    If intYear Mod 400 = 0 Then
        isLeapYear = True
    ElseIf intYear Mod 4 = 0 And intYear Mod 100 <> 0 Then
        isLeapYear = True
    End If

End Function

أرى العديد من المفاهيم الرائعة التي تشير إلى فهم إضافي واستخدام وظائف التاريخ الرائعة للتعلم من ...من حيث كفاءة الكود ..ضع في اعتبارك رمز الجهاز المطلوب لتنفيذ الوظيفة

بدلاً من وظائف التاريخ المعقدة ، استخدم فقط وظائف عدد صحيح سريع إلى حد ما تم بناؤها على Goto وأظن أن شيئًا ما أدناه أسرع

  Function IsYLeapYear(Y%) As Boolean
     If Y Mod 4 <> 0 Then GoTo NoLY ' get rid of 75% of them
     If Y Mod 400 <> 0 And Y Mod 100 = 0 Then GoTo NoLY
     IsYLeapYear = True

لالي:

 End Function

إجابة متأخرة لمعالجة سؤال الأداء.

ليرة تركية/دكتور:ال الرياضيات الإصدارات حول أسرع بـ 5 مرات


أرى مجموعتين من الإجابات هنا

  1. التفسير الرياضي لتعريف السنة الكبيسة
  2. استخدم وظائف التاريخ/الوقت في Excel للكشف عن 29 فبراير (تنقسم هذه إلى معسكرين:تلك التي تبني تاريخًا كسلسلة، وتلك التي لا تفعل ذلك)

لقد أجريت اختبارات زمنية على جميع الإجابات المنشورة، واكتشفت الرياضيات الأساليب حول أسرع بـ 5 مرات من أساليب التاريخ/الوقت.


بعد ذلك قمت ببعض التحسينات على الأساليب وتوصلت إلى (صدق أو لا تصدق Integer أسرع بشكل هامشي من Long وفي هذه الحالة، لا أعرف السبب.)

Function IsLeapYear1(Y As Integer) As Boolean
    If Y Mod 4 Then Exit Function
    If Y Mod 100 Then
    ElseIf Y Mod 400 Then Exit Function
    End If
    IsLeapYear1 = True
End Function

للمقارنة، خطرت لي (فارق بسيط جدًا عن النسخة المنشورة)

Public Function IsLeapYear2(yr As Integer) As Boolean
    IsLeapYear2 = Month(DateSerial(yr, 2, 29)) = 2
End Function

تم خصم إصدارات التاريخ/الوقت التي تنشئ تاريخًا كسلسلة لأنها أصبحت أبطأ مرة أخرى.

وكان الاختبار للحصول على IsLeapYear لسنوات 100..9999، تكررت 1000 مرة

نتائج

  • نسخة الرياضيات:640 مللي ثانية
  • إصدار التاريخ/الوقت:3360 مللي ثانية

وكان رمز الاختبار

Sub Test()
    Dim n As Long, i As Integer, j As Long
    Dim d As Long
    Dim t1 As Single, t2 As Single
    Dim b As Boolean

    n = 1000

    Debug.Print "============================="
    t1 = Timer()
    For j = 1 To n
    For i = 100 To 9999
        b = IsYLeapYear1(i)
    Next i, j
    t2 = Timer()
    Debug.Print 1, (t2 - t1) * 1000

    t1 = Timer()
    For j = 1 To n
    For i = 100 To 9999
        b = IsLeapYear2(i)
    Next i, j
    t2 = Timer()
    Debug.Print 2, (t2 - t1) * 1000
End Sub

إليك خيارًا بسيطًا آخر.

Leap_Day_Check = Day(DateValue("01/03/" & Required_Year) - 1)

إذا كانت Leap_Day_Check = 28 فهي ليست سنة كبيسة، وإذا كانت 29 فهي كذلك.

يعرف VBA التاريخ الذي يسبق الأول من مارس خلال عام ولذلك سيحدده ليكون إما 28 أو 29 فبراير بالنسبة لنا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top