Wie findet man das Schaltjahr in C programmatisch?

Ich habe mit C ein Programm erstellt, um herauszufinden, ob das eingegebene Jahr ein Schaltjahr ist oder nicht. Aber leider funktioniert es nicht gut. Es sagt ein Jahr ist ein Sprung und das vorhergehende Jahr ist kein Sprung.

#include #include int yearr(int year); void main(void) { int year; printf("Enter a year:"); scanf("%d",&year); if(!yearr(year)) { printf("It is a leap year."); } else { printf("It is not a leap year"); } getch(); } int yearr(int year) { if((year%4==0)&&(year/4!=0)) return 1; else return 0; } 

Nachdem ich die Kommentare gelesen hatte, habe ich meinen Code wie folgt geändert:

 #include #include int yearr(int year); void main(void) { int year; printf("Enter a year:"); scanf("%d",&year); if(!yearr(year)) { printf("It is a leap year."); } else { printf("It is not a leap year"); } getch(); } int yearr(int year) { if((year%4==0) { if(year%400==0) return 1; if(year%100==0) return 0; } else return 0; } 

    Deine Logik, ein Schaltjahr zu bestimmen, ist falsch. Dies sollte dir helfen (von Wikipedia):

     if year modulo 400 is 0 then is_leap_year else if year modulo 100 is 0 then not_leap_year else if year modulo 4 is 0 then is_leap_year else not_leap_year 

    x modulo y bedeutet den Rest von x geteilt durch y . Zum Beispiel ist 12 Modulo 5 2.

    Effizientester Schaltjahrtest:

     if ((year & 3) == 0 && ((year % 25) != 0 || (year & 15) == 0)) { /* leap year */ } 

    Dieser Code ist in C, C ++, C #, Java und vielen anderen C-ähnlichen Sprachen gültig. Der Code verwendet einen einzelnen TRUE / FALSE-Ausdruck, der aus drei separaten Tests besteht:

    • 4. Jahr Test: year & 3
    • 100. Jahrestest: year % 25
    • 400. Jahrestest: year & 15

    Eine vollständige Diskussion darüber, wie dieser Code funktioniert, erscheint unten, aber zuerst wird eine Diskussion des Wikipedia-Algorithmus gefordert:

    Der Wikipedia-Algorithmus ist INEFFIZIENT / UNZUWEISBAR

    Wikipedia hat einen Pseudo-Code-Algorithmus veröffentlicht (siehe: Wikipedia: Leap Year – Algorithmus ), der ständigen Bearbeitungen, Meinungen und Vandalismus ausgesetzt war.

    Implementieren Sie WIKIPEDIA-ALGORITHMUS NICHT!

    Einer der ältesten (und ineffizientesten) Wikipedia-Algorithmen erschien wie folgt:

     if year modulo 400 is 0 then is_leap_year else if year modulo 100 is 0 then not_leap_year else if year modulo 4 is 0 then is_leap_year else not_leap_year 

    Der obige Algorithmus ist ineffizient, weil er immer die Tests für das 400. und 100ste Jahr durchführt, sogar für Jahre, die schnell den “4-Jahres-Test” (den Modulo 4-Test) nicht bestehen würden – was 75% der Zeit ist! Indem wir den Algorithmus neu anordnen, um den Test im 4. Jahr durchzuführen, beschleunigen wir die Dinge erheblich.

    “EFFIZIENTER” PSEUDO-CODE-ALGORITHMUS

    Ich habe Wikipedia den folgenden Algorithmus zur Verfügung gestellt (mehr als einmal):

     if year is not divisible by 4 then not leap year else if year is not divisible by 100 then leap year else if year is divisible by 400 then leap year else not leap year 

    Dieser “höchst effiziente” Pseudocode ändert einfach die Reihenfolge der Tests, so dass zuerst die Division durch 4 erfolgt, gefolgt von den weniger häufig vorkommenden Tests. Da “Jahr” nicht zu 75% durch vier geteilt wird, endet der Algorithmus nach nur einem Test in drei von vier Fällen.

    HINWEIS: Ich habe verschiedene Wikipedia-Redakteure bekämpft, um den dort veröffentlichten Algorithmus zu verbessern. Viele Anfänger und professionelle Programmierer kommen aufgrund der Top-Suchmaschinenauflistungen schnell auf die Wikipedia-Seite und implementieren den Wikipedia-Pseudocode ohne weitere Nachforschungen. Wikipedia-Redakteure lehnten ab und löschten jeden Versuch, den veröffentlichten Algorithmus zu verbessern, zu kommentieren oder sogar nur zu Fuß zu notieren. Anscheinend ist es das Problem des Programmierers, Effizienz zu finden. Das mag stimmen, aber viele Programmierer sind zu eilig, um solide Forschung zu betreiben!

    DISKUSSION DES “EFFIZIENTEN” LEAP-JAHR-TESTS

    Bitweises UND anstelle von Modulo:

    Ich habe zwei der Modulo-Operationen im Wikipedia-Algorithmus durch bitweise UND-Operationen ersetzt. Warum und wie?

    Das Ausführen einer Modulo-Berechnung erfordert eine Division. Beim Programmieren eines PCs denkt man nicht oft darüber nach, aber beim Programmieren von 8-Bit-Mikrocontrollern, die in kleine Geräte eingebettet sind, kann es vorkommen, dass eine Divisionsfunktion nicht nativ von der CPU ausgeführt werden kann. Bei solchen CPUs ist die Division ein mühsamer process, der repetitives Schleifen, Bitverschiebung und Addieren / Subtrahieren umfasst, was sehr langsam ist. Es ist sehr wünschenswert zu vermeiden.

    Es stellt sich heraus, dass der Modulo der Zweierpotenzen abwechselnd mit einer bitweisen UND-Verknüpfung erreicht werden kann (siehe: Wikipedia: Modulo-Operation – Performance Issues ):

    x% 2 ^ n == x & (2 ^ n – 1)

    Viele optimierende Compiler konvertieren solche Modulo-Operationen in bitweise UND für Sie, aber weniger fortgeschrittene Compiler für kleinere und weniger populäre CPUs. Bitwise-AND ist eine einzelne statement auf jeder CPU.

    Indem wir die modulo 4 und modulo 400 Tests durch & 3 und & 15 ersetzen (siehe unten: “Factoring um Mathe zu reduzieren”) können wir sicherstellen, dass die schnellsten Code Ergebnisse ohne einen viel langsameren Divisionsvorgang erzielt werden.

    Es gibt keine Zweierpotenz, die gleich 100 ist. Daher sind wir gezwungen, die Modulooperation für den 100. Jahrestest weiter zu verwenden, jedoch wird 100 durch 25 ersetzt (siehe unten).

    Factoring zur Vereinfachung der Mathematik:

    Neben der Verwendung von bitweisem UND zum Ersetzen von Modulo-Operationen können Sie zwei weitere Konflikte zwischen dem Wikipedia-Algorithmus und dem optimierten Ausdruck feststellen:

    • modulo 100 wird durch modulo 25
    • modulo 400 wird durch & 15

    Der 100. Jahrestest verwendet modulo 25 anstelle von modulo 100 . Wir können dies tun, weil 100 Faktoren auf 2 x 2 x 5 x 5 hinausgehen. Da der 4. Jahr-Test bereits nach Faktoren von 4 sucht, können wir diesen Faktor von 100 eliminieren, wobei 25. übrig bleibt. Diese Optimierung ist wahrscheinlich unbedeutend für fast jede CPU-Implementierung ( da sowohl 100 als auch 25 in 8-Bit passen).

    Der 400. Jahrestest verwendet & 15 was modulo 16 . Wiederum können wir dies tun, weil 400 Faktoren zu 2 x 2 x 2 x 2 x 5 x 5 eliminiert werden. Wir können den Faktor von 25 eliminieren, der durch den 100. Jahrestest getestet wird, wobei 16. 16 nicht weiter reduziert werden kann, weil 8 ist ein Faktor von 200, so würde das Entfernen von mehr Faktoren ein unerwünschtes Positiv für ein 200. Jahr erzeugen.

    Die 400-Jahr-Optimierung ist für 8-Bit-CPUs sehr wichtig, erstens, weil sie eine Aufteilung vermeidet; aber, wichtiger, weil der Wert 400 eine 9-Bit-Zahl ist, die in einer 8-Bit-CPU viel schwieriger zu behandeln ist.

    Kurzschluss logische UND / ODER-Operatoren:

    Als letzte und wichtigste Optimierung werden die logischen UND-Verknüpfungen (‘&&’) und OR (‘||’) verwendet (siehe: Wikipedia: Kurzschlussauswertung ), die in den meisten C-ähnlichen Sprachen implementiert sind . Kurzschlussoperatoren werden so genannt, weil sie sich nicht die Mühe machen, den Ausdruck auf der rechten Seite zu bewerten, wenn der Ausdruck auf der linken Seite für sich allein das Ergebnis der Operation diktiert.

    Zum Beispiel: Wenn das Jahr 2003 ist, dann ist year & 3 == 0 falsch. Es gibt keine Möglichkeit, dass die Tests auf der rechten Seite des logischen UND das Ergebnis wahr machen können, also wird nichts anderes ausgewertet.

    Bei der Durchführung des 4. Jahrestests wird nur der 4. Jahrestest (ein einfaches bitweises UND) zu drei Vierteln (75 Prozent) der Zeit ausgewertet. Dies beschleunigt die Programmausführung erheblich, zumal es die für den 100-jährigen Test notwendige Aufteilung (die Modulo-25-Operation) vermeidet.

    HINWEIS auf Eltern Platzierung

    Ein Kommentator fühlte, dass Klammern in meinem Code fehlplatziert waren und schlug vor, dass die Unterausdrücke um den logischen AND-Operator gruppiert wurden (statt um das logische ODER), wie folgt:

     if (((year & 3) == 0 && (year % 25) != 0) || (year & 15) == 0) { /* LY */ } 

    Das obige ist falsch. Der logische UND-Operator hat eine höhere Priorität als das logische ODER und wird zuerst mit oder ohne die neuen Klammern ausgewertet. Klammern um die logischen UND-Argumente haben keine Auswirkung. Dies könnte dazu führen, dass die Untergruppen vollständig eliminiert werden:

     if ((year & 3) == 0 && (year % 25) != 0 || (year & 15) == 0) { /* LY */ } 

    Aber in beiden obigen Fällen wird die rechte Seite des logischen ODER (der 400. Jahrestest) fast jedes Mal ausgewertet (dh Jahre, die nicht durch 4 und 100 teilbar sind). Daher wurde irrtümlich eine nützliche Optimierung eliminiert.

    Die Klammern in meinem ursprünglichen Code implementieren die am besten optimierte Lösung:

     if ((year & 3) == 0 && ((year % 25) != 0 || (year & 15) == 0)) { /* LY */ } 

    Hier wird das logische ODER nur für Jahre ausgewertet, die durch 4 teilbar sind (wegen des Kurzschlusses AND). Die rechte Seite des logischen ODER wird nur für Jahre ausgewertet, die durch 4 und 100 teilbar sind (wegen des Kurzschluss-ODER).

    HINWEIS FÜR C / C ++ PROGRAMMER

    C / C ++ – Programmierer empfinden diesen Ausdruck möglicherweise als optimierter:

     if (!(year & 3) && ((year % 25) || !(year & 15))) { /* LY */ } 

    Dies ist nicht mehr optimiert! Während die expliziten Tests == 0 und != 0 entfernt werden, werden sie implizit und werden noch ausgeführt. Schlimmer noch, der Code ist in stark typisierten Sprachen wie C #, in denen year & 3 zu einem int ausgewertet wird, nicht länger gültig, aber die logischen Operatoren AND ( && ), OR ( || ) und NOT ( ! ) Erfordern bool Argumente.

     int isLeapYear(int year) { return (year % 400 == 0) || ( ( year % 100 != 0) && (year % 4 == 0 )); } 

    Obwohl die Logik, die zuerst durch 400 geteilt wird, tadellos ist, ist sie nicht so effizient wie die Division durch 4. Sie können das mit der Logik tun:

     #define LEAPYEAR(y) ((y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0)) 

    Dies wird für jeden Wert durch 4 geteilt, aber für 3/4 endet der Test dort. Für das 1/4, das den ersten Test besteht, teilt es sich dann durch 100 und eliminiert 24/25 Werte; für die verbleibende 1 von 100 teilt es sich ebenfalls um 400 und kommt mit einer endgültigen Antwort. Zugegeben, das ist keine große Ersparnis.

    Dies könnte die richtige Lösung sein. Algorithmus auf Wikipedia gegeben ist nicht richtig.

     -(BOOL)isLeapYear: (int)year{ if(year%4==0){ if(year%100!=0){ return YES; } else if(year%400!=0){ return YES; } else return NO; } else return NO; } 

    Das Problem mit Ihrem Code ist, dass Sie einen Wert ungleich Null von Jahr yearr wenn Sie denken, dass das Jahr ein Schaltjahr ist. Also brauchst du das nicht ! in Ihrer if-statement.

    Aus Wikipedia Artikel zum Schaltjahr :

     if (year modulo 4 is 0) and (year modulo 100 is not 0) or (year modulo 400 is 0) then is_leap_year else not_leap_year 

    http://www.edu/depts/skywise/leapyear.html

    Schaltjahr-Regeln

    Jedes Jahr gibt es ein Schaltjahr, dessen Zahl perfekt durch vier teilbar ist – mit Ausnahme von Jahren, die durch 100 teilbar und nicht durch 400 teilbar sind. Der zweite Teil der Regel wirkt sich auf Jahrhundertjahre aus. Beispielsweise; die Jahrhundertjahre 1600 und 2000 sind Schaltjahre, aber die Jahrhundertjahre 1700, 1800 und 1900 sind nicht. Das bedeutet, dass drei von vierhundert Jahren zwischen den Schaltjahren acht Jahre liegen.

      if(year%400 ==0 || (year%100 != 0 && year%4 == 0)) { printf("Year %d is a leap year",year); } else { printf("Year %d is not a leap year",year); } 

    Ändere es wie oben. Lesen Sie auch dies .

    
         #einschließen 
         void main (ungültig)
         {
             int Jahr;
             printf ("Geben Sie ein Jahr ein, um zu überprüfen, ob es sich um ein Schaltjahr handelt \ n");
             scanf ("% d", & Jahr);
             if (Jahr% 400 == 0) / * Warum mod 400 * /
                 printf ("% d ist ein Schaltjahr \ n", Jahr);
             sonst wenn (Jahr% 100 == 0) / * Warum mod 100 * /
                 printf ("% d ist kein Schaltjahr \ n", Jahr);
             sonst wenn (Jahr% 4 == 0)
                 printf ("% d ist ein Schaltjahr \ n", Jahr);
             sonst
                 printf ("% d ist kein Schaltjahr \ n", Jahr);
    
         }
    
    
     I used this code: #include  int main() { int yr; printf ("Enter a year \n"); scanf ("%d", &yr); if (yr%400 == 0) printf("\n LEAP YEAR."); else if (yr%4==0 && yr%100!=0) printf("\n LEAP YEAR."); else printf ("\n NOT LEAP YEAR."); } 

    Wie andere auch erwähnt haben, ist die Bedingung für das Schaltjahr nicht korrekt. Es sollte:

     int yearr(int year) { if(((year%4 == 0) && (year%100 !=0)) || (year%400==0)) return 1; else return 0; } 

    Lesen Sie hier, wie Sie das Schaltjahr in C überprüfen können .

    Kevins Antwort bietet einen optimalen 8-Operationstest (mit XOR unter Verwendung von Konstanten), aber wenn Sie nach einem etwas besser lesbaren suchen, versuchen Sie diesen 9 Operationstest.

     year % 4 == 0 && !((year % 100 == 0) ^ (year % 400 == 0)) 

    Wahrheitstabelle für (year % 100 == 0) ^ (year % 400 == 0)

      (year % 100 == 0) ^ (year % 400 == 0) 100 doesnt divide year . F only 100 divides year . T 100 and 400 divides year . F 

    Jetzt !(year % 100 == 0) ^ (year % 400 == 0) gibt, was Sie wollen.

    Berechne max / letzter Tag für Monat: 1..12, Jahr: 1..3999

     maxDays = month == 2 ? 28 + ((year & 3) == 0 && ((year % 25) != 0 || (year & 15) == 0)) : 30 + ((month & 1) ^ (month > 7)); 

    #define is_leap(A) !((A) & 3)

    Achte nur darauf, dass du kein negatives Jahr eingibst 🙂