Einsendung:

Lösungsvorschlag

Hier die ultimative datumIstGueltig-Funktion, die zwar funktioniert, durch die ich aber selber nicht mehr ganz durchsteige. Hat jemand noch was komplizierteres?

int datumIstGueltig(int tag,int monat,int jahr)
{
   return (((monat>=1) && (monat<=12)) && (tag>=1) && (((tag<=31) && ((monat=1) ¦¦
      (monat=3) ¦¦ (monat=5) ¦¦ (monat=7) ¦¦ (monat=8) ¦¦ (monat=10) ¦¦ (monat=12))) ¦¦
      ((tag<=30) && ((monat=4) ¦¦ (monat=6) ¦¦ (monat=9) ¦¦ (monat=11))) ¦¦ ((monat=2)
      && (((0 ¦¦ (jahr%4==0)) && !(jahr%100==0)) ¦¦ (jahr%400==0) && (tag<=29)) ¦¦ !((0
      ¦¦ (jahr%4==0)) && !(jahr%100==0)) ¦¦ (jahr%400==0) && (tag<=28)))));
};

Ich habe eine andere Lösung.
Wenn jemand noch einen Einfall hat, wie das noch kürzer geht, dann bitte eine Mail an mich! Das muß nicht fertig ausprogrammiert sein, nur eine Idee reicht schon. Wenn es dann verwendbar ist, werde ich den Code schon zustande bringen.

bool datumIstGueltig(int tag,int monat,int jahr)
{
   return monat>0&&monat<13&&tag>0&&tag<32&&(tag<31¦¦(monat>7!=monat%2==1))
   &&(monat!=2¦¦(tag<30&&(((jahr%4==0&&jahr%100!=0)¦¦jahr%400==0)¦¦tag<29)));
};

Getestet habe ich sie, indem ich eine einfache Lösung genommen habe, und die einfache Funktion in datumIstGueltigSec umgenannt habe. Das folgende Testprogramm gab dann alle Daten aus, bei denen die komplizierte Funktion noch Fehler machte.

void main()
{
   for(int jahr=1500;jahr<2100;jahr=jahr+1)
      for(int monat=1;monat<=12;monat=monat+1)
         for(int tag=-2;tag<35;tag=tag+1)
            if(datumIstGueltig(tag,monat,jahr)!=datumIstGueltigSec(tag,monat,jahr))
               cout<<"Fehler bei: "<<tag<<'.'<<monat<<'.'<<jahr<<endl;
};

Ich empfehle Ihnen dringend, überall, wo es sich anbietet, solche kleinen Testfunktionen zu schreiben, um sicherzugehen, daß Ihre Programme fehlerfrei laufen.
Welche der beiden Lösungen jetzt komplizierter ist, läßt sich schwer sagen, weil man durch beide nicht mehr durchsteigt.
Zum Vergleich hier die schöne Lösung:

int wievieleTageHatMonat(int monat,int jahr)
{
   if(monat==2)
      if(!istSchaltjahr(jahr))
         return 28;
      else
         return 29;
   else if(monat==4¦¦monat==6¦¦monat==9¦¦monat==11)
      return 30;
   else 
      return 31;
};
bool datumIstGueltig(int tag,int monat,int jahr)
{
   if(monat<1return false;
   if(monat>12return false;
   if(tag<1return false;
   if(tag>wievieleTageHatMonat(monat,jahr)) return false;
   return true;
};

 Allgemein gilt, daß kürzere Lösungen besser zu verstehen sind, man darf es mit der Kürze nur nicht übertreiben. Die schöne Lösung ist in dieser Hinsicht wohl optimal. Bei logischen Ausdrücken würde ich aber immer erst einmal prüfen, ob nicht ein if eingesetzt werden könnte, das die Ausdrücke einfacher macht. Das geht nämlich immer!

Aber ist

   if (xy==1return 1else return 0;

wirklich

   return (xy==1);

vorzuziehen?

Nein. Nie. Auch die Klammern fliegen weg:

   return xy==1;

Es ist also abzuwägen, wie kompliziert die logischen Ausdrücke werden dürfen.
Gegen etwas wie

   if (tag<1 ¦¦ tag>29return false;

ist bestimmt nichts einzuwenden, denn es ist einfacher zu verstehen als

   if (tag<1return false;
   if (tag>29return false;

aber bereits bei

(jahr%4==0&&jahr%100!=0)¦¦jahr%400==0

ist die Grenze erreicht, wo der Ausdruck mit if vereinfacht werden sollte.
Außerdem sollte man es mit der Mathematik nicht übertreiben:
Der Ausdruck

   monat==2¦¦monat==4¦¦monat==6¦¦monat==9¦¦monat==11

ist *deutlich* einfacher zu verstehen als

   monat>7==monat%2==1

, obwohl beide dasselbe ausdrücken, solange monat zwischen 1 und 12 liegt.

PS: Ich liebe logische Operatoren!

Das ist gut. Man muß den Feind kennen, um ihn wirksam bekämpfen zu können.



Falls Ihnen Fehler im Text auffallen oder Sie Verbesserungsvorschläge haben, dann schicken Sie mir bitte eine Mail. Ich werde mich dann sofort darum kümmern.
[aktuelle Version] [inhalt] [index]      [Fehlerkorrektur, Verbesserungsvorschlag]

© Volkard Henkel <volkard@normannia.de>, last update: 08/25/00