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.
# -*- 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 == 'n': again = False print 'Bye !' break elif ans == '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 not in ['ui', 'benchmark']: usage() if sys.argv == '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 == 'benchmark': try: nb_size = int(sys.argv) tries = int(sys.argv) 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