Use of logical operators in Leap year problem

2.1k Views Asked by At

I am quite new in this programming world and my question may sound silly but can anyone explain difference between following 2 codes.

Code 1

    int yr;
    printf("enter the respective year=\n");
    scanf("%d", &yr);
    if(yr%400==0 || yr%100!=0 && yr%4==0)
        printf("It is a leap year\n");
    else
        printf("It is not a leap year\n");

    return 0;

Code 2

    int yr;
    printf("enter the respective year=\n");
    scanf("%d", &yr);
    if((yr%100==0 && yr%400==0) || yr%4==0)
        printf("It is a leap year\n");
    else
        printf("It is not a leap year\n");

    return 0;

I think both should work well but when I executed them then only Code 1 is giving right answers.

3

There are 3 best solutions below

1
On BEST ANSWER

The condition in the if statement

if(yr%400==0 || yr%100!=0 && yr%4==0)

that can be equivalently rewritten using parentheses like

if ( ( yr%400==0 ) || ( yr%100!=0 && yr%4==0 ) )

means that a leap year is the year that either divisible by 400 or divisible by 4 and at the same time is not divisible by 100.

For example the year 1900 is not a leap year because it is not divisible by 400 and on the other hand is divisible by 100.

The condition in this if statement

if((yr%100==0 && yr%400==0) || yr%4==0)

means that any year divisible by 4 is a leap year due to the second sub-expression yr%4==0 that always yields logical true for any year divisible by 4. So it is even unimportant what will be the logical result of the first sub-expression (yr%100==0 && yr%400==0) because any number divisible by 100 and 400 is divisible at the same time by 4.

So the second if statement is logically wrong. It accepts the year 1900 as a leap year.

0
On

There is a collision of two complications: the leap year rule itself and the logical operators. The && binds tighter than || but that is not even the deeper problem.

A (nested) if...else might be overkill.

The conditional ?: seems perfect. I can leave out the ==0 plus the NOT !=. Just place the 0/1 at the right spot. This gives a regular pattern:

int isleap(int y) {

    return
    y%4 ?            // normal year?
      0              // done
      : y%100 ?      // Candidate. Not a century?
         1           // normal leap
         : y%400 ?   // Century. normal one?
            0        // 100 normal century   
            : 1      // 400 special century
    ;                     // return's semicolon
}

The ternary conditional expression is between the logical expressions and the if-statement. With logical expressions it is a bit hard to safely gather both "1" cases together.

"Oh but this takes more lines."

Yes. Or do you want to copy paste that one-line logical expression regularly? And it can be put on a line, looks only 20% worse than &&||-versions.

(nobody really asked, talking with myself)

"Oh it is a whole function"

inline is an official function-specifier, if speed matters.


Why I am saying is log. expr. are tricky in this case. The "standard" 4-100-400-no-parens-middle-not formula:

 return y%4 == 0 && y%100 != 0 || y%400 == 0;

makes the compiler suggest parens around the && part. But even with wrong parens you get the right result. Set theory? Inverted double exception?

0
On

expressions

(yr%400==0 || yr%100!=0 && yr%4==0)   /* (yr%400==0 || (  yr%100!=0 && yr%4==0))*/

and

( yr%100!=0 && yr%4==0 || yr%400==0 )   /* ( (yr%100!=0 && yr%4==0) || yr%400==0 )*/

are correct, but to to avoid confusion better to use parentheis. Both are evaluated(grouped for calculation) differently as shown in the comment. Evaluation order is based on operator precedence rules(&& has precedence over ||).