[Tutor] re: Leap year problem

Michael Janssen Janssen@rz.uni-frankfurt.de
Tue Jan 14 19:30:32 2003


On 14 Jan 2003, ahimsa wrote:
> On Sun, 2003-01-12 at 21:32, Don Arnold wrote:
> >
> > def isLeapYear(year):
> >     if year % 400 == 0:
> >         return 1
> >     elif year % 100 == 0:
> >         return 0
> >     elif year % 4 == 0:
> >         return 1
> >     else:
> >         return 0
> >
>
> OK - that makes sense to me, I thought by seeing if it divided by '100'
> first it would eliminate it from going through the rest of the
> conditions. Are there any quick and dirty guidelines about how one makes
> those kinds of determinations when constructing conditional statements -
> e.g. test large numbers first, or test for the rarely occurring variable
> first, or ... ?

both these guidelines won't do the decision which condition should be
tested first proper.

The point is: Test first the condition which can't be overrunned by
another. Then the decision which would only be overrunned by the already
tested condition. Last take the remaining condition (what else? :-)

(year %4 == 0) is a need not a must for "leapness", therefore it is not
enough just to test this.
(year %400 == 0) is a must (and a need) for "leapness". When this test is
true year is leap for sure.
(year %100 == 0) is (very different ;-) a *possible* and not-neccessary
condition for non leapness. possible: only if not (year %400 == 0);
not-neccessary: also years not (year %100 == 0) can be non-leap.

It remembers me a bit to the common mathematical and philosophical concept
to distinguish between "necessary" and "sufficient" conditions (sorry i'm
not sure if these are the proper english terms; it's "notwendig" and
"hinreichend" in german). "truth table" is, if applicable (?):

  necessary | sufficient | outcoming
1.    x     |     x      |   true
2.    x     |            |   possible, futher testing needed
3.          |     x      |   impossible
4.          |            |   impossible

By now my little attempt to explain the logic of leapness testing has gone
a bit off topic ;-)

The above solution of leapness testing is easier than this
necessary-sufficient-stuff. But take a look at the library function isleap
in modul calendar:
def isleap(year):
    """Return 1 for leap years, 0 for non-leap years."""
    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)

this is the necessary ("year % 4 == 0") and sufficient ("(year % 100 != 0
or year % 400 == 0)") pattern (note: truth-table entry 3. can't occour)!

Sidenote: In the case of a programm with to many conditions mixed up in
hairy crossdependencies *I* would decide not to think to much about that
and take the most common condition first. Your programm will very well be
buggy but you spare programmingtime and runtime.

Michael

I don't know how clear that question is. If it isn't
> clear, let me know and I'll see if I can rephrase it. For instance, the
> above guideline is, as you've stated, check initially for the specifics
> of a case and then move to the more general. Would that apply in most
> cases with a conditional suite?

no: to quote myself: "note: truth-table entry 3. can't occour". Without
that testing the specific case could mean you test the sufficient
condition and leave out the necessary. I leave it to your homework to
understand this ;-) It's late.