Número Armstrong en Java

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 Java. 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 los siguiente métodos.

  • El método principal.
  • El método para verificar si un número es Armstrong o no.
  • El método para contar la cantidad de dígitos de un número.

Método Principal

El método 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 el método \texttt{es\_Armstrong}. A continuación explicamos paso a paso la implementación de este método.

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{MAX\_VALUE} que se encuentra en la clase \texttt{Integer}.

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 declara e inicializa dentro de la instrucción con el valor de 1 a través de la expresión \texttt{int i=1}. El ciclo \texttt{for} repetirá el bloque de instrucciones mientras la variable de control sea menor o igual al valor \texttt{MAX\_VALUE}. Por esto se coloca como condición del \texttt{for} \texttt{i<=Integer.MAX\_VALUE} 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++}.

package lista_de_armstrong;

public class Lista_de_Armstrong {

    public static void main(String[] args) {
        for (int i = 1; i <= Integer.MAX_VALUE; i++) {
 
        }
    } 

Validación de número Armstrong

Para verificar si un número es Armstrong usaremos el método \texttt{es\_Armstrong}. No nos preocupamos en este paso por la implementación de este método, lo analizaremos con detalle en la siguiente sección. Solo nos interesa saber lo que hace. El método \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.

package lista_de_armstrong;

public class Lista_de_Armstrong {

    public static void main(String[] args) {
        for (int i = 1; i <= Integer.MAX_VALUE; i++) {
            if (es_Armstrong(i)) {
                System.out.printf("%d%n", i);
            }
        }
    } 

Verificación si un número es Armstrong

Procederemos ahora a analizar la implementación del método \texttt{es\_Armstrong}. Este método recibe como parámetro \texttt{numero} de tipo \texttt{int} que asumimos es un número mayor que cero. El método 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 este método 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 el método \texttt{cuenta\_digitos} que nuevamente no nos preocuparemos de implementar en esta sección. Asumiremos que este método 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.

    private static boolean es_Armstrong(int numero) {
        int total_digitos = cuenta_digitos(numero);
        for (int 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. 

    private static boolean es_Armstrong(int numero) {
        int total_digitos = cuenta_digitos(numero);
        int copia_numero = numero;
        for (int 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 el método \texttt{pow} que permite elevar un número a cualquier potencia en Java. Para poder usar este método, se debe importar desde \texttt{java.lang.Math}.

Al finalizar, el método 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, el método retornará el valor de \texttt{true}. En caso esto no se cumpla la comparación, el método retornará el valor de \texttt{false}.

    private static boolean es_Armstrong(int numero) {
        int total_digitos = cuenta_digitos(numero);
        int copia_numero = numero;
        int suma_de_potencias = 0;
        for (int 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 Java» podrá encontrar las otras versiones y la explicación detallada de cada una de ellas.

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

Conclusión

Hemos presentado en este artículo, una propuesta de solución al listado de los números Armstrong usando Java. 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 en Java, el mejor libro que hay es Effective Java de Joshua Bloch. Uno de los libros favoritos de los que se inician en Java es Java: Learn Java in One Day and Learn It Well de  Jamie Chan.

Deja una respuesta

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