[SOLVED] Having trouble understanding if x % 4 == 0 and ( x % 100 == 0 and x % 400) == 0

Issue

This Content is from Stack Overflow. Question asked by Vitor Niskier

leap_year = int(input('Year: '))
initial_year = leap_year

while True:
leap_year += 1
if leap_year % 4 == 0 and (leap_year % 100 == 0 and leap_year % 400) == 0:
    print(f'The next leap year after {initial_year} is {leap_year}')
    break

Can someone explain to me how this: if leap_year % 4 == 0 and (leap_year % 100 == 0 and leap_year % 400) == 0:
is different from this: if leap_year % 4 == 0 and leap_year % 100 == 0 and leap_year % 400 == 0:



Solution

It’s confusing how there’s an == 0 at the end, which is functionally the same as putting not before that part. It’s also confusing how leap_year % 400 isn’t directly compared against anything, unlike the other modulo operations.*

It’d be clearer to rewrite it:

leap_year % 4 == 0 and not (leap_year % 100 == 0 and leap_year % 400 != 0)

If we apply De Morgan’s law, it might be even clearer:

leap_year % 4 == 0 and (leap_year % 100 != 0 or leap_year % 400 == 0)

Lastly, you could remove the parentheses at this point, but it’s better for readability to keep them.

Now it should be obvious how it differs from the other condition you mentioned.


* What actually happens there is that the and evaluates leap_year % 100 == 0 and if it’s falsy, it yields the result, i.e. False; if it’s truthy, it yields the result of leap_year % 400, i.e. an int in range(0, 400, 100). That gets compared against the == 0 at the end, and for False it works because False == 0.


This Question was asked in StackOverflow by Vitor Niskier and Answered by wjandrea It is licensed under the terms of CC BY-SA 2.5. - CC BY-SA 3.0. - CC BY-SA 4.0.

people found this article helpful. What about you?