Número Armstrong en Python

Más ejercicios resueltos

Si deseas revisar más ejercicios resueltos, haz click en el siguiente botón. 

A continuación presentamos una alternativa de solución al problema de generación del listado de números Armstrong en Python. Si deseas ver el enunciado del problema, haz click en el siguiente enlace

A continuación procederemos a presentar una alternativa de solución al problema de generación del listado de números Armstrong. Usaremos para tal solución el paradigma de programación modular. Aplicaremos además la técnica de diseño descendente. Se implementarán las siguiente funciones.

  • La función principal.
  • La función para verificar si un número es Armstrong o no.
  • La función para contar la cantidad de dígitos de un número.

Programa Principal

La función principal básicamente lo que realiza es el control de flujo para recorrer la lista de enteros y para cada número, verifica si es Armstrong o no, usando para este fin la función \texttt{es\_Armstrong}. A continuación explicamos paso a paso la implementación de esta función.

Control de flujo

El control de flujo busca recorrer los números naturales en el rango 1..límite, siendo el límite 2^{31}-1. Hemos puesto dicho límite pues en la mayoría de los lenguajes de programación, corresponde con el máximo entero que se puede representar. En Python realizamos la potenciación con el operador \texttt{**}.

Para el control de flujo se ha utilizado la instrucción \texttt{for}. Se utiliza como variable de control a la variable \texttt{i}. Como la instrucción \texttt{for} en Python recorre toda lista de secuencias, iteraremos en una secuencia de números. Para esto usamos la función \texttt{range(1, limite+1)}, esta función generará la secuencia entre [1..limite]

limite = 2**31-1
for i in range(1, limite+1): 

Validación de número Armstrong

Para verificar si un número es Armstrong usaremos la función \texttt{es\_Armstrong}. No nos preocupamos en este paso por la implementación de esta función, la analizaremos con detalle en la siguiente sección. Solo nos interesa saber lo que hace esta función. La función \texttt{es\_Armstrong} retornará el valor de \texttt{True} si es que el número pasado como parámetro es efectivamente Armstrong, en caso contrario retornará el valor de \texttt{False}

Usamos este hecho para usar una selectiva simple e imprimir el número en caso sea Armstrong, implementando una especie de filtro. Este filtro solamente dejará pasar los números Armstrong.

limite = 2**31-1
for i in range(1, limite+1):
    if es_Armstrong(i):
        print(i) 

Verificación si un número es Armstrong

Procederemos ahora a analizar la implementación de la función \texttt{es\_Armstrong}. Esta función recibe como parámetro \texttt{numero}que asumimos es un número mayor que cero. El programa principal debe garantizar esto. Retorna el valor \texttt{True} si la suma de cada uno de sus dígitos elevado al número total de dígitos es igual al mismo número y \texttt{False} en caso contrario.

Analizaremos esta función en 3 partes:

  • Primero analizaremos el control de flujo.
  • Luego veremos cómo obtenemos cada dígito del número.
  • Finalmente hallaremos la sumatoria.

Control de flujo

Dado que tenemos que hallar la suma de todos los dígitos elevado a la cantidad de dígitos de número, necesitamos obtener cada uno de los dígitos del número. Como esta operación es repetitiva, usaremos una estructura algorítmica iterativa. En este caso en particular necesitaremos conocer la cantidad de dígitos que tiene el número, por lo tanto aprovechamos esto para el control de flujo.

En primer lugar lo que hacemos es calcular la cantidad de dígitos del número. Almacenaremos este valor en la variable \texttt{total\_digitos}. El cálculo lo realizaremos usando la función \texttt{cuenta\_digitos} que nuevamente no nos preocuparemos de implementar en esta sección. Asumiremos que esta función existe y nos retorna la cantidad de dígitos del número pasado como parámetro.

Lo siguiente es iterar tantas veces como dígitos tenga el numero. Usamos la instrucción \texttt{for} que encaja perfectamente para el control de flujo que necesitamos realizar. Usaremos la función \texttt{range} para generar una secuencia que contenga \texttt{total\_digitos} valores. En esta oportunidad no nos va interesar el valor de los números generados, solamente la cantidad de ellos.

 
def es_Armstrong(numero):
    total_digitos = cuenta_digitos(numero)
    for i in range(0, total_digitos): 

Obtención del dígito

Una vez que hemos controlado el flujo, procederemos a obtener cada uno de los dígitos del número. La forma de obtener los dígitos de un número es haciendo divisiones del número entre 10. El problema de hacer esto es que el número lo vamos transformando y luego no podremos compararlo para determinar si es Armstrong o no. Por este motivo, lo primero que realizamos es obtener una copia del número que deseamos analizar. Esta copia la guardamos en la variable \texttt{copia\_numero}. De esta forma, podemos modificar esta copia manteniendo el valor del parámetro intacto.

Luego, en cada iteración usamos esta copia para obtener los dígitos del número. Para obtener el dígito que corresponde con la iteración usamos el operador de módulo o resto \texttt{\%}. La operación \texttt{copia\_numero\ \%\ 10} lo que hace es obtener el dígito que está más a la derecha en el número, el dígito de las unidades. Por ejemplo si el número fuera 153, la operación 153\ \%\ 10 retornaría el valor de 3, el dígito de las unidades.

Una vez hallado el dígito, debemos de actualizar nuestra copia del número. ¿Cómo hacemos dicha actualización? Realizando una división entera entre el numero y 10. Por ejemplo si el número fuera 153, la operación 153\ //\ 10 retornaría el valor de 15, el número sin el dígito ya procesado previamente.  Recuerde que el operador \texttt{//} permite realizar la división entera en Python.

def es_Armstrong(numero):
    total_digitos = cuenta_digitos(numero)
    copia_numero = numero
    for i in range(0, total_digitos):
        digito = copia_numero % 10
        copia_numero //= 10 

Suma de potencias

El último paso a realizar es encontrar la sumatoria. Para esto usaremos una variable a la que hemos denominado \texttt{suma\_de\_potencias}. Como es una sumatoria, la hemos inicializado con el valor de 0.

En cada iteración, básicamente lo que se hace es, incrementarla con el valor del dígito obtenido elevado a la cantidad total de dígitos. Para esto usamos el opereador \texttt{**} que permite elevar un número a cualquier potencia en Python.

Al finalizar, la función retorna el valor de una comparación de igualdad. Los valores que se comparan son el número pasado como parámetro y la sumatoria hallada, si ambos valores son iguales, la función retornará el valor de \texttt{True}. En caso esto no se cumpla la comparación, la función retornará el valor de \texttt{False}.

def es_Armstrong(numero):
    total_digitos = cuenta_digitos(numero)
    copia_numero = numero
    suma_de_potencias = 0
    for i in range(0, total_digitos):
        digito = copia_numero % 10
        copia_numero //= 10
        suma_de_potencias += digito**total_digitos
    return numero == suma_de_potencias 

Cuenta dígitos

El último paso a implementar para terminar el análisis de este ejercicio, es el cálculo de la cantidad de dígitos de un número. En realidad existen diversas maneras de calcular la cantidad de dígitos que posee un número. En esta oportunidad usaremos la versión usando los logaritmos pues se ha demostrado que es la más eficiente de todas, pero en nuestro artículo «Cantidad de dígitos de un número en Python» podrá encontrar las otras versiones y la explicación detallada de cada una de ellas.

def cuenta_digitos(numero):
    if numero == 0:
        return 1
    return int(math.log10(numero) + 1) 

Conclusión

Hemos presentado en este artículo, una propuesta de solución al listado de los números Armstrong usando Python. Se ha utilizado para el diseño algorítmico la técnica del diseño descendente y se ha controlado  el flujo en los módulos usando estructuras selectivas e iterativas. Podrá descargar la solución propuesta en el repositorio GitHub de iterando++ a través del siguiente enlace

Hemos preparado otros artículos adicionales en donde describimos al detalle la implementación de este problema en PSeInt y otros lenguajes de programación. Te invitamos a leer los siguientes artículos de iterando++

Si te interesa profundizar más en el desarrollo en Python, los dos mejores libros que se han escrito son Learning Python de Mark Lutz y Python Crash Course de Eric Matthes.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *