# Return True if num is within 2 of a multiple of 10

Is there a way to make my code simpler/more pythonic?

Given a non-negative number "num", return True if num is within 2 of a multiple of 10. Note: (a % b) is the remainder of dividing a by b, so (7 % 5) is 2. See also: Introduction to Mod

near_ten(12) → True

near_ten(17) → False

near_ten(19) → True

def near_ten(num):

a = num % 10
if  (10 - (10-a)) <= 2 or (10 - a) <= 2:
return True
else:
return False


I'm no Python expert, so I can't say if this is more or less Pythonic than @MrSmith42's, but it seems just a bit clearer, without the negation - though that may be offset by the modular arithmetic trick. Anyway...

def near_ten(num):
return (num + 2) % 10 <= 4


And to @Curt's point, it seems a bit faster than all but the numpy version, though without a copy of IPython at hand, I had trouble replicating his tests in quite the same way.

• I really like the idea to shift the problem so it can be simply solved by one compare. – MrSmith42 Jul 31 '15 at 6:57

You could simplify your code to make it faster and also avoid the 'if-else' construct:

def near_ten(num):
a = num % 10
return 8 <= a or 2 >= a


Here's another version: (Thanks to the comment of @mkrieger1)

def near_ten(num):
return not(2 < (num % 10) < 8)


I think the name of the function is misleading. Maybe you should rename it to something like: near_multiple_of_ten(num)

• Unfortunately, 8 <= a <= 2 doesn't work, but not 2 < a < 8 does! – mkrieger1 Jul 10 '15 at 12:32

I thought MrSmith42's answers were really compact and readable. But I wanted to see if they were faster.

Also, I wanted to test numpy for comparison. Here's my numpy version:

def near_ten5(num_list):
a = np.mod(num_list, 10)
return np.logical_or(2 >= a, 8 <= a)


All the versions presented so far:

def near_ten1(num):
a = num % 10
if  (10 - (10-a)) <= 2 or (10 - a) <= 2:
return True
else:
return False

def near_ten2(num):
a = num % 10
return 8 <= a or 2 >= a

def near_ten3(num):
return not(2 < (num % 10) < 8)

def near_ten4(num):
return abs(5 - num % 10) >= 3

def near_ten5(num_list):
a = np.mod(num_list, 10)
return np.logical_or(2 >= a, 8 <= a)


Code to test them for accuracy and speed:

from random import randint, random
import timeit
import numpy as np

accuracy_test = [-3.4, -2, 0.1, 22, 23]
for f in [near_ten1, near_ten2, near_ten3, near_ten4, near_ten5]:
print [f(x) for x in accuracy_test]

timer_test = [random()*randint(0, 20) for _ in xrange(10**5)]

%timeit [near_ten1(n) for n in timer_test]
%timeit [near_ten2(n) for n in timer_test]
%timeit [near_ten3(n) for n in timer_test]
%timeit [near_ten4(n) for n in timer_test]
%timeit near_ten5(timer_test)


Output:

[False, True, True, True, False]
[False, True, True, True, False]
[False, True, True, True, False]
[False, True, True, True, False]
[False, True, True, True, False]
10 loops, best of 3: 36.5 ms per loop
10 loops, best of 3: 26.5 ms per loop
10 loops, best of 3: 25.2 ms per loop
10 loops, best of 3: 28.1 ms per loop
100 loops, best of 3: 3.85 ms per loop


Unsurprisingly, the numpy solution is the fastest, but is admittedly less elegant than what I call near_ten3(), which is the answer from MrSmith42 / mkrieger1.

A couple of other minor comments:

1. Docstrings would be good!
2. All the current functions will fail if complex numbers are provided (and obviously also if non-numbers are provided).
• Why do you have the numpy version do 100 loops and everything else only do 10? – PhatWrat Jul 10 '15 at 18:04
• timeit decides how many loops to do based on how long things are taking. Since numpy was faster it did more loops. – Curt F. Jul 10 '15 at 18:21
• @Curt While numpy is clearly the fastest - by almost an order of magnitude - I think it got a bit of an unfair leg up in your benchmarks, due to the loop over timer_test being inside the function call while all the others had it outside. A similar change to the version in my answer shaved off about a third of the runtime. Nonetheless, very nice analysis work! – bibach Jul 11 '15 at 22:18
• Good point bibach -- it was something I wondered about a bit, but your ocmment convinced me: before I post future benchmarking I'll try to do a better job of "apples to apples" comparison. – Curt F. Jul 12 '15 at 5:30