# Notes On Python: Truth and Modulo

Today I learnt how to be less verbose when using the `%` operator in Python.

SPOILER: I learnt this while trying to apply a functional approach to the first problem on Project Euler and I describe my answer here.

So, to set the scene, the first problem on Project Euler is presented as such:

“If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.

Find the sum of all the multiples of 3 or 5 below 1000.”

I initially answered this with the following function:

``````def sum_mul_three_five(end_num):
"""
Returns the sum of all the multiples of 3 or 5 below end_num
"""
total = []
for num in range(end_num):
if num % 3 == 0 or num % 5 == 0:
total.append(num)
return sum(total)
``````

This code is pretty self-explanatory, but the line I want to focus on is the `if` statement. The `%` operator returns the remainder of a division, and is popularly used in Python for such things as sorting even numbers. For instance:

``````>>> numbers = range(10)
>>> numbers
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> for number in numbers:
...     if number % 2 == 0:
...         print number
...
0
2
4
6
8
``````

Here we iterate through a simple list of numbers. The `if` statement uses the `%` operator to check what the remainder will be when each number is divided by `2`. If there is no remainder, ie. the result is `0` then the number is equally divided by `2` and therefore `even`

``````>>> for number in range(10):
...     if number % 2 == 0:
...         print "%d is even" % number
...     else:
...         print "%d is odd" % number
...
0 is even
1 is odd
2 is even
3 is odd
4 is even
5 is odd
6 is even
7 is odd
8 is even
9 is odd
``````

So, in my solution for Project Euler I am using `%` to test whether each number is divisible by 3 or 5. When I tried to refactor this with a more Functional approach using a list comprehension, I got this long mess:

``````def sum_mul_three_five(end_num):
"""
Returns the sum of all the multiples of 3 or 5 below end_num
"""
total = []
[total.append(num) for num in range(end_num) if num % 3 == 0 or num % 5 == 0]
return sum(total)
``````

Eeek! As I have been told, while this works, it’s probably the wrong way. What I didn’t realise is that we can be more concise with the modulo statements, and use them as a `True/False` test. This is because `0` and `1`, the two results we can get from using `%`, equate to `False` and `True` respectively.

EDIT See Below…

This may seem simple but it’s perhaps overlooked when learning Python, especially for those without a CS background, such as myself, or perhaps my view of the wood was blocked by the trees.

``````>>> 1 == True
True
>>> 0 == False
True
``````

Therefore `if num % 3 == 0` is specifying the condition is met when the remainder of dividing a number by 3 is `0`, which also corresponds to `False`, or `not True`.

``````>>> 0 != True
True
>>> 1 != True
False
``````

Now, the `if` condition of an `if/else` conditional expression is met when the condition is `True`, or `not False`. This is where my mind started to fold over into itself. So, to return the numbers divisible by `3` in an `if` statement the result needs to be `True`, whereas with `%` it is `False`

``````>>> for number in range(10):
...     if number % 3:
...         print number
...
1
2
4
5
7
8
>>> for number in range(10):
...     if not number % 3:
...         print number
...
0
3
6
9
``````

Basically we’re replacing `== 0` with the concept of `True` and `False`, which ends up as this:

``````def sum_mul_three_five(end_num):
"""
Returns the sum of all the multiples of 3 or 5 below end_num
"""
total = []
[total.append(num) for num in range(end_num) if not num % 3 or not num % 5]
return sum(total)
``````

Which is saying return the number if it is `not True`, ie. `False`, a condition met when the remainder is `0` when the number is divided by `3`.

Though this is still a bit ugly, so let’s simplify the rest a bit…

``````def sum_mul_three_five(end_num):
"""
Returns the sum of all the multiples of 3 or 5 below end_num
"""
return sum([num for num in range(end_num) if not num % 3 or not num % 5])
``````

Ahh yes ain’t that fresh. Everybody wants to get down like that.

I think that makes sense, I hope it does.

EDIT Ok, so I totally overlooked that the result of `%` isn’t restricted to `0` or `1`, so this example is perhaps not as black and white as I first believed.

``````>>> for number in range(10):
...     print number % 2
...
0
1
0
1
0
1
0
1
0
1
>>> for number in range(10):
...     print number % 3
...
0
1
2
0
1
2
0
1
2
0
>>> for number in range(10):
...     print number % 5
...
0
1
2
3
4
0
1
2
3
4
``````

So, what happens with remainders that aren’t `0` or `1`? Well, they are interpreted as `False` in this case

``````>>> for number in range(10):
...     if number % 3:
...         print "False: \tNumber: %d \tRemainder: %d" % (number, number % 3)
...     else:
...         print "True: \tNumber: %d \tRemainder: %d" % (number, number % 3)
...
True:   Number: 0       Remainder: 0
False:  Number: 1       Remainder: 1
False:  Number: 2       Remainder: 2
True:   Number: 3       Remainder: 0
False:  Number: 4       Remainder: 1
False:  Number: 5       Remainder: 2
True:   Number: 6       Remainder: 0
False:  Number: 7       Remainder: 1
False:  Number: 8       Remainder: 2
True:   Number: 9       Remainder: 0
``````

I have to admit, this hasn’t totally clicked in my brain yet. I mean, I get it, but the whole is it True, is it False? thing is a little hard to keep track of y’know.