Which is "more correct (logically)"? Specific to Leap Year, not in general.
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)
return year % 4 == 0 and year % 100 != 0 or year % 400 == 0
False and True or True
False and (True or True)
False and False or True
False and (False or True)
Answer: Include Parentheses
John Kugelman explains why they are 2 separate logical tests as opposed to 3, last 2 should be grouped together:
The version with parentheses matches this two-pronged rule best.
return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0) ^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ (1) (2)
As it happens, removing the parentheses does not break the code, but it leads to an unnatural version of the rules:
That's not the way I think of the leap year rule.
Inspired by mrdomoboto, 100/400 are the exception!:
Year must be divisible by 4, 100 is an exception and 400 is an exception of the exception but they are still one exception in total (see above). This means that if year is not divisible by 4 then the whole thing must be False. The only way to ensure this is to put parens around the exception because
False and bool will always return False.
See below examples of this from JBallin
False and True or True #True False and (True or True) #False
False and False or True #True False and (False or True) #False
Adam Smith translated the english into code:
All years divisible by 4 are leap years, unless they're divisible by 100 and NOT divisible by 400, which translates to:
return y % 4 == 0 and not (y % 100 == 0 and y % 400 != 0)
not(a and b) = (not a or not b)
To convert the parens into the desired answer:
#move "not" inside parens return y % 4 == 0 and (not y % 100 == 0 or not y % 400 != 0) #convert parens using "DML" return y % 4 == 0 and (y % 100 != 0 or y % 400 == 0)