Número Armstrong en C

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 ANSI C. 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.

Función 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 todos los números naturales. Pero, ¿cómo hacemos para recorrer todos los números naturales? En realidad no podemos recorrer todos los números naturales pues existe una limitación por la cantidad de bits que se utilizan para representar cada tipo de dato. Usaremos el tipo de dato \texttt{int} para recorrer a los numeros en el rango. El máximo valor que se puede representar con este tipo de dato se encuentra definido en la constante \texttt{INT\_MAX} la cual se encuentra declarada en el archivo de cabecera \texttt{limits.h}.

Para el control de flujo se ha utilizado la instrucción \texttt{for}. Se utiliza como variable de control a la variable \texttt{i} la cual se inicializa dentro de la instrucción con el valor de 1. El ciclo \texttt{for} repetirá el bloque de instrucciones mientras la variable de control sea menor o igual al valor \texttt{INT\_MAX}. Por esto se coloca como condición del \texttt{for} \texttt{i<=INT\_MAX} Al final de cada iteración, la variable se incrementa en 1, esto lo indicamos en la última expresión del \texttt{for}, \texttt{i++}.

#include <stdio.h>
#include <limits.h>

int main() {
    int i;
    for (i = 1; i <= INT_MAX; i++)
        
    return 0;
} 

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 1 si es que el número pasado como parámetro es efectivamente Armstrong, en caso contrario retornará el valor de 1

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.

#include <stdio.h>
#include <limits.h>

int es_Armstrong(int numero);

int main() {
    int i;
    for (i = 1; i <= INT_MAX; i++)
        if (es_Armstrong(i))
            printf("%d\n", i);
    return 0;
} 

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} de tipo \texttt{int} que asumimos es un número mayor que cero. La función principal debe garantizar esto. Retorna el valor \texttt{1} 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{0} 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. Usamos la variable de control \texttt{i} la cual ha sido inicializada en 1 e iteramos mientras dicha variable sea menor o igual al \texttt{total\_digitos}. En cada ciclo o paso, incrementamos en 1 la variable de control.

int es_Armstrong(int numero) {
    int total_digitos = cuenta_digitos(numero);
    int i;
    for (i = 1; i <= total_digitos; i++) {
        
    }
} 

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. 

int es_Armstrong(int numero) {
    int total_digitos = cuenta_digitos(numero);
    int i;
    int copia_numero = numero;
    for (i = 1; i <= total_digitos; i++) {
        int 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 la función \texttt{pow} que permite elevar un número a cualquier potencia en ANSI C. Para poder usar esta función, se debe incluir el archivo de cabecera \texttt{math.h}.

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{1}. En caso esto no se cumpla la comparación, la función retornará el valor de \texttt{0}.

int es_Armstrong(int numero) {
    int total_digitos = cuenta_digitos(numero);
    int i;
    int copia_numero = numero;
    int suma_de_potencias = 0;
    for (i = 1; i <= total_digitos; i++) {
        int digito = copia_numero % 10;
        copia_numero /= 10;
        suma_de_potencias += pow(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 C» podrá encontrar las otras versiones y la explicación detallada de cada una de ellas.

int cuenta_digitos(int numero) {
    if (numero == 0)
        return 1;
    return log10(numero) + 1;
} 

Conclusión

Hemos presentado en este artículo, una propuesta de solución al listado de los números Armstrong usando ANSI C. 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 quieres profundizar en el lenguaje ANSI C, no hay mejor libro que C Programming Language de Brian Kernighan  y Dennis Ritchie. Es un libro clásico escrito por el creador del lenguaje C. Uno de los libros favoritos de los que inician en ANSI C es  C Programming Absolute Beginner’s Guide de Greg Perry y Dean Miller.

Deja una respuesta

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