I've read this question about computing the digital root of some integer, and wondered how it would look like in Python.
As a reminder,
"If you take the digits of any number and add them together, and then add the digits of the resulting number together, and continue doing that until you get a single digit, that single digit is the digital root of the original number."
This is not much about the algorithm performance itself, since it was shown in this answer that instead of summing the digits, you could do a simple division by 9 to get the same result. The question is more about the readability, elegance, and pythonicity (if this word exists) of my code. I checked its correctness with a tool from Thonky.
More, I'd be interested in knowing your opinion on the way I deal with sys.argv
, the user interaction, and the benchmarking.
Finally, is it OK to use the int
type for such long numbers? It seems to work fine even with 1000-digit numbers, but intuitively it shouldn't...
Any suggestion would be highly appreciated. Thanks.
digitalroot.py
# -*- encoding: utf-8 -*-
import time
import random
import sys
def request_user_number():
while True:
try:
nb = int(raw_input('Enter a number\n'))
return nb
except (ValueError, NameError):
print 'This is not a number. Try again.'
def request_user_again():
while True:
try:
ans = str(raw_input('New computation? (y/n)\n')).lower()
if ans[0] == 'n':
again = False
print 'Bye !'
break
elif ans[0] == 'y':
again = True
break
else:
print 'Did not understand. Try again.'
except IndexError:
print 'Say something.'
return again
def digits_generator(nb):
tmp = nb
while tmp != 0:
yield tmp % 10
tmp /= 10
def digital_root(nb):
if nb < 10:
return nb
else:
s = 0
for d in digits_generator(nb):
s += d
return digital_root(s)
def usage():
print 'Wrong usage'
print '\'python digitalroot.py ui\' for a user chosen number'
print '\'python digitalroot.py benchmark nb_size tries\' for benchmarking'
exit(1)
if __name__ == '__main__':
if len(sys.argv) < 2 or sys.argv[1] not in ['ui', 'benchmark']:
usage()
if sys.argv[1] == 'ui':
again = True
while again:
nb = request_user_number()
print 'Computing digital root of', nb
start_time = time.clock()
dr = digital_root(nb)
end_time = time.clock()
print nb, '-->', dr, '(time :', end_time-start_time, 's)'
again = request_user_again()
elif sys.argv[1] == 'benchmark':
try:
nb_size = int(sys.argv[2])
tries = int(sys.argv[3])
except (ValueError, NameError, IndexError):
usage()
global_start = time.clock()
s = 0
for i in xrange(tries):
nb = random.randint(10**(nb_size-1), 10**nb_size-1)
start_time = time.clock()
d = digital_root(nb)
end_time = time.clock()
s += end_time-start_time
if random.randint(1, tries/5) == 1:
print 'Random control : i =', i, ',', nb, '-->', d
print nb_size, 'digits,', tries, 'tries'
print s, 'seconds (average =', float(s)/tries, 's/try)'
print 'Total benchmark time :', time.clock()-global_start