Gyakorlati alapok

A kényeskedés netovábbja: a többszörös feltételmegadás (szökőév)

 

Az előző fejezetben többszörös feltételmegadással bosszantottam a Tisztelt Olvasót. A szökőév kiszámításában ez fog most tetőzni, ugyanis a helyes végeredményhez 4 db feltétel egyidejű teljesülését kell beállítanunk.

 

Kis elméleti előzmény: a szökőév egy olyan speciális év, amely általában 4 évente +1 napot tartalmaz (február 24.). Erre azért van szükség, mert a csillagászati év és az 1582 óta működő Gergely-, másik nevén Gregorián-naptár között folyamatosan korrigálandó, időbeli eltérések vannak. A szökőév nem tévesztendő össze a szökőmásodpercekkel, amelyeket -ugyanilyen okból-, a csillagászati naphosszhoz szintén korrigálnak.

 

Először is ne ijedjünk meg, mert az igényt a Java alkotói is észrevették, ezért a szökőév kiszámításának algoritmusát már beépítették a java.util csomagba. Eléréséhez a csomagot (vagy annak részét) be kell importálnunk a projektbe (import java.util.*;):

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

public class Main {
    public static void main(String[] args) {
    int ev = 2000;
    GregorianCalendar gc = new GregorianCalendar();
    System.out.print(gc.isLeapYear(ev));
    }
}

 

Végeredmény:

true

 

A szökőévet int típusként adjuk meg, mert a függvény (isLeapVear(int)) ezt kéri. A függvény visszatérési értéke kétféle lehet: igaz (true) vagy hamis (false). Igaz, ha a szám szökőév, másként hamis értéket ad vissza. A kiíráskor tudjuk ezt ellenőrizni.

 

Természetesen a naptárobjektum létrehozása után (GregorianCalendar gc = new GregorianCalendar()) nemcsak ezt az egy, hanem számos további, naptár és dátum jellegű metódust tudunk elérni; ezt egy külön fejezetben fogjuk megvizsgálni.

 

A szökőév kézi vizsgálatához a következő feltételek ismeretére van szükségünk:

  • nagyobb 1582-nél (ev > 1582),

  • osztható 4-gyel (ev % 4 == 0),

  • nem osztható 100-zal (ev % 100 != 0),

  • osztható 400-zal (ev % 400 == 0).

A feltétel megadásában azonban van 1 kis trükk. Mivel nincs olyan szám, amelyik ugyan osztható 400-zal, de NEM osztható 100-zal, ezért közöttük nem logikai ÉS (&&), hanem VAGY (||) műveletet kell alkalmaznunk:

 

if ((ev > 1582) && (ev % 4 == 0) && (ev % 100 != 0) || (ev % 400 == 0))

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


public class Main {
    public static void main(String[] args) {
    int ev = 2000;
    if ((ev > 1582) && (ev % 4 == 0) && (ev % 100 != 0) || (ev % 400 == 0)){
        System.out.println ("Az év szökőév.");
    }
    else
        System.out.println ("Az év NEM szökőév.");
    }
}

 

Végeredmény:

Az év szökőév.

 

Most pedig írjunk egy olyan algoritmust, amely a gépi (beépített Java) és a saját (nevezzük kézinek) szökőévszámítást hasonlítja össze! A kód mindezt külön fogja elvégezni, ám az összehasonlításhoz egy flag-re, egy segédváltozóra is szükségünk van, ez a boolean szokoEv lesz. Értéke alapértelmezésben false, true értékre pedig akkor lesz állítva, ha kézi ellenőrzéskor az év szökőévnek bizonyul. Erre azért van szükség, mert a gépi függvény (gc.isLeapYear(ev)) szintén boolean értéket ad vissza, tehát nekünk ezt a 2 azonos típusú változót kell összehasonlítanunk:

 

if (gc.isLeapYear(ev) == szokoEv)

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

public class Main {
    public static void main(String[] args) {
    int ev = 1999;
    boolean szokoEv = false;
        if (ev > 1582 && ev % 4 == 0 && (ev % 100 != 0 || ev % 400 == 0)){
            szokoEv = true;
            System.out.println ("Saját kód: az év szökőév.");
        }
        else
            System.out.println ("Saját kód: az év NEM szökőév.");

    GregorianCalendar gc = new GregorianCalendar();
    if (gc.isLeapYear(ev)){
        System.out.println ("Java-kód: az év szökőév.");
    }
    else
        System.out.println ("Java-kód: az év NEM szökőév.");

    if (gc.isLeapYear(ev) == szokoEv){
        System.out.println ("Egyeznek az eredmények.");
    }
    else
        System.out.println ("Nem egyeznek az eredmények.");
    }
}

 

Végeredmény:

Saját kód: az év NEM szökőév.
Java-kód: az év NEM szökőév.
Egyeznek az eredmények.

 

Csakis akkor van probléma, ha nem egyeznek az eredmények és ez sajnos igen hamar be is következett...

 

www.informatika-programozas.hu - Ezt most meg kell tanulni!

 

...ugyanis a kód tesztelésekor megdöbbenve vettem észre, hogy a gépi függvény figyelmen kívül hagyja az 1582-es kezdődátumot; a gc.isLeapYear() néhány 1582 alatti dátum esetén -például 1200-, true értéket ad vissza!

 

Ezt a fogyatékosságot tehát korrigálni ahhoz, hogy a gépi és kézi összehasonlítás korrekt maradjon. Ekkor +1 segédváltozót kellett bevezetnem (boolean szokoEvGepi = false;), illetve gépi ellenőrzéskor a kérdéses +1 feltételt (if (gc.isLeapYear(ev) && ev > 1582)). Illetve -mivel megbizonyosodtunk arról, hogy a gépi függvény nem mindig ad korrekt eredményt-, a gépi és kézi összehasonlításkor már csak a saját kezelésű segédváltozók kerültek be a logikai döntésbe (if (szokoEvGepi == szokoEvKezi)):

 

www.informatika-programozas.hu - Futtatható Java-kód!

 

 

 

 

 

 

 


import java.util.*;

public class Main {
    public static void main(String[] args) {
    int ev = 1200;
    boolean szokoEvKezi = false;
    boolean szokoEvGepi = false;
    if (ev > 1582 && ev % 4 == 0 && (ev % 100 != 0 || ev % 400 == 0)){
        szokoEvKezi = true;
        System.out.println ("Saját kód: az év szökőév.");
    }
    else
        System.out.println ("Saját kód: az év NEM szökőév.");

    GregorianCalendar gc = new GregorianCalendar();
    if (gc.isLeapYear(ev) && ev > 1582){
        szokoEvGepi = true;
        System.out.println ("Java-kód: az év szökőév.");
    }
    else
        System.out.println ("Java-kód: az év NEM szökőév.");

    if (szokoEvGepi == szokoEvKezi){
        System.out.println ("Egyeznek az eredmények.");
    }
    else
        System.out.println ("Nem egyeznek az eredmények.");
    }
}

 

Segédlet: