Optimizing code – Part 4

The next mini optimization we can do is to bail out earlier because when summing the number and we overshoot the original then we can stop immediately. For example 9 ** 6 is a big number and so with bigger numbers it makes sense to bail out earlier.

import sys
from datetime import datetime

POWERS = [0,1,2,3,4,5,6,7,8,9]
LENGTH = 1

def recalculate_powers() -> None:
    global POWERS
    for i,v in enumerate(POWERS):
        POWERS[i] = i * v

def is_narcissistic(x: int) -> bool:
    global LENGTH, POWERS
    org = x
    digits = []
    total = 0
    while x > 0:
        _, x = digits.append(x % 10), x // 10
    cur_length = len(digits)
    if cur_length != LENGTH:
        LENGTH = cur_length
        recalculate_powers()
    for i in digits:
        total += POWERS[i]
        if total > org:
            return False
    return total == org

def find_narcissistic_numbers(desired: int) -> None:
    for x in range(1,sys.maxsize):
        if is_narcissistic(x):
            desired -= 1
        if desired == 0:
            return

start = datetime.utcnow()
find_narcissistic_numbers(28)
print(datetime.utcnow() - start)

The time for this code to run on my laptop is: 0:06:21.202479

To compare this to the original run of the naive implementation is, which was 0:08:09.315972. Even on my slow hardware, it still resulted in a speed up of about 25%.

#code #python