JBallin - 4 months ago 27

Python Question

Which is "more correct (logically)"? *Specific to Leap Year, not in general*.

- With Parentheses

`return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)`

- Without

`return year % 4 == 0 and year % 100 != 0 or year % 400 == 0`

`and`

`or`

Observe the effects of parentheses:

`False and True or True`

#True

False and (True or True)

#False

`False and False or True`

#True

False and (False or True)

#False

Without parentheses, there are scenarios where even though

Answer

Answer: **Include Parentheses**

John Kugelman explains why they are 2 separate logical tests as opposed to 3, last 2 should be grouped together:

- Year must be divisible by 4.
- Year must not be visible by 100, unless it's divisible by 400.

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:

- Year must be divisible by 4, but not by 100; or
- Year must be divisible by 400.

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)
```

JBallin cited De Morgan's Laws:

```
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)
```