Cantidad de dígitos de un número en C

Más ejercicios resueltos

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

A continuación presentamos 5 alternativas de solución al problema de contar la cantidad de dígitos de un número en ANSI C. Si deseas ver el enunciado del problema, haz click en el siguiente enlace

A continuación presentamos 5 alternativas de solución usando las distintas formas de la estructura algorítmica iterativa, la recursión, así como el uso de los logaritmos

Función principal

La función principal tendrá como objetivo la lectura de datos e invocación a la función \texttt{cuenta\_digitos}. No existe ninguna validación que realizar al número n, esto debido a que el enunciado del problema indica que el dominio del número corresponde al conjunto de los números enteros. La lectura en ANSI C la realizaremos a través de la función \texttt{scanf} y el valor leído se almacenará en la variable \texttt{numero}. Recuerde que para poder usar la función \texttt{scanf}, debemos de incluir el archivo de cabecera \texttt{stdio.h} en el programa.

Debido a que las distintas alternativas de solución que se analizarán, esperan que el número que se pase como parámetro sea un número natural, se actualiza numero leído con su valor absoluto. ¿Por qué esto es necesario? Esto en realidad corresponde con el detalle de la implementación de cada alternativa de solución. Lo veremos más adelante en cada solución, pero lo que podemos ir adelantando es que todas ellas solo funcionarán para los números naturales (numero>0). Para obtener el valor absoluto de un número usamos la función \texttt{abs}. La declaración de esta función se encuentra en el archivo de cabecera \texttt{stdlib.h}.

#include <stdio.h>
#include <stdlib.h>

int cuenta_digitos(int n);

int main() {
    int numero;
    printf("Ingrese un número: ");
    scanf("%d", &numero);
    
    numero=abs(numero);
    printf("El número tiene %d dígito(s)\n", cuenta_digitos(numero));
    return 0;
} 

Cuenta dígitos

Procederemos ahora a implementar la función \texttt{cuenta\_digitos}. Esta función recibe como parámetro un número natural \texttt{numero} mayor o igual a cero. Retorna la cantidad de dígitos del número pasado como parámetro.

Procederemos a presentar detalladamente la implementación del método \texttt{cuenta\_digitos} usando en primer lugar la estructura algorítmica iterativa con entrada controlada. Detallaremos tres puntos en particular:

  • El control de flujo.
  • El conteo de los dígitos.
  • El tratamiento del número cero.

Control de flujo

Como en todo problema iterativo, el primer punto a gestionar es el control de flujo. La versión que implementaremos se basa en la iteración y se busca que en cada iteración se cuenta un dígito del número que está siendo analizado. Entonces, ¿cómo realizamos el control de flujo? 

  1. Variable de control. El control de gestionaremos a través del mismo parámetro \texttt{numero}. Usaremos a \texttt{numero} como nuestra variable de control de la iteración.
  2. Condición de la iteración. Dado que queremos ir extrayendo un dígito en cada iteración, seguiremos iterando mientras existan dígitos para sacar. En otras palabras, mientras \texttt{numero>0}. Cuando \texttt{numero} contenga el valor de cero, asumiremos que no existirán más dígitos por extraer y la iteración deberá de terminar.
  3. Actualización de la variable de control. Al final de cada iteración debemos actualizar \texttt{numero}. Debemos quitarle un dígito a la variable de control \texttt{numero}. Esto se logra simplemente dividiendo entre 10 al número en cuestión. Utilizamos para este fin la operación de asignación \texttt{/=}. Recuerde que \texttt{numero/=10} equivale a \texttt{numero=numero/10}.
int cuenta_digitos(int numero){
    while(numero>0){

        numero/=10;
    }
} 

Conteo de dígitos

El siguiente paso es definir una variable en donde se llevará la cuenta de los dígitos que se van a ir extrayendo. Esta variable, comúnmente llamada contador, la hemos identificado con \texttt{total\_digitos}. Básicamente lo que hacemos es incrementar su valor en uno en cada iteración. Contando los dígitos que vamos obteniendo del número. Para incrementar el contador hemos utilizado el operador de incremento \texttt{++}. Recuerde que \texttt{total\_digitos++} equivale a \texttt{total\_digitos=total\_digitos+1}.

int cuenta_digitos(int numero){
    int total_digitos = 0;
    while(numero>0){
        total_digitos++;
        numero/=10;
    }
} 

Caso particular del número 0

Hay un caso particular que debemos manejar en nuestro programa. Se da cuando el parámetro \texttt{numero} es igual a cero. Dado que en la versión iterativa implementada, usamos como condición de iteración \texttt{numero>0}, nunca se ejecutará cuando \texttt{numero=0}, por lo que la variable \texttt{total\_digitos} contendrá el valor de \texttt{0}. Entonces, en esta situación, asignamos el valor de \texttt{1} a la variable \texttt{total\_digitos}. Para esto usamos un estructura selectiva simple inmediatamente después del ciclo iterativo.

int cuenta_digitos(int numero){
    int total_digitos = 0;
    while(numero>0){
        total_digitos++;
        numero/=10;
    }
    if (total_digitos==0)
        total_digitos++;
    return total_digitos;
} 

Cuenta dígitos: versión con for

Como ya hemos comentado anteriormente en iterando++, la instrucción \texttt{for} en ANSI C funciona de forma muy similar a una iterativa con entrada controlada. La principal diferencia es que la instrucción \texttt{for} la inicialización de la variable de control, la condición y la actualización de la variable de control, se realiza en un mismo lugar. Esta característica hace que sea una de las instrucciones preferidas para iterar de muchos programadores ya que facilita el entendimiento del código.

En este caso se ha utilizado la instrucción \texttt{ for ( ; numero > 0; numero /= 10)}. La parte de la inicialización está vacía dado que no se ha realizado ella pues usamos el parámetro como variable de control. La condición es \texttt{numero>0} y la actualización de la variable de control es \texttt{numero /= 10}.

int cuenta_digitos(int numero) {
    int total_digitos = 0;
    for (; numero > 0; numero /= 10)
        total_digitos++;
    if (total_digitos == 0)
        total_digitos++;
    return total_digitos;
} 

Cuenta dígitos: versión con do-while

La versión que veremos ahora es la versión con salida controlada. Usaremos en este caso la instrucción \texttt{do-while}. A primera impresión es una versión muy parecida a la realizada con la instrucción \texttt{while} pero como podrán notar, en esta versión no hacemos la verificación del caso particular del número 0. Pero, ¿por qué no es necesario? Dado que se realiza el control en la salida, el bloque de instrucciones se ejecutará por lo menos una vez. Entonces, aunque el parámetro \texttt{numero} contenga el valor de 0, la iteración se ejecutará.

int cuenta_digitos(int numero) {
    int total_digitos = 0;
    do {
        total_digitos++;
        numero /= 10;
    } while (numero > 0);
    return total_digitos;
} 

Cuenta dígitos: versión recursiva

Función recursiva

La siguiente versión que implementaremos será la versión recursiva. El caso base será cuando \texttt{numero==0}. En esta situación se retorna el valor de \texttt{0}. En el caso recursivo se retorna \texttt{1} + la llamada recursiva pero actualizando el parámetro \texttt{numero}. El parámetro \texttt{n} lo dividimos entre 10 antes de hacer la invocación. 

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

Función principal

La versión recursiva que hemos implementado posee un problema. No controla el caso cuando el \texttt{numero} pasado como parámetro es cero. En este situación hemos optado por hacer dicho control en la función principal. De esta forma si el número leído  es \texttt{0}, se imprime el valor de \texttt{1}. En caso contrario se imprime el valor que retorna la función recursiva. 

Hemos usado el operador ternario \texttt{?:} para realizar la condicional. El operador ternario posee 3 operandos. Funciona de forma muy similar a una selectiva. Si el primer operando se evalúa como verdadero, se retorna el segundo operando, en caso contrario se retorna el tercer operando. La ventaja que ofrece es que permite escribir condicionales de una forma muy simple en una línea.

Otra opción que hubiésemos podido tomar en cuenta es encapsular esta verificación del cero en otra función. Haciendo transparente este detalle de implementación.

#include <stdio.h>
#include <stdlib.h>

int cuenta_digitos(int n);

int main() {
    int numero;
    printf("Ingrese un número: ");
    scanf("%d", &numero);

    numero = abs(numero);
    printf("El número tiene %d dígito(s)\n", numero == 0 ? 1 : cuenta_digitos(numero));
    return 0;
} 

Cuenta dígitos: versión usando logaritmos

Otra versión muy usada para contar la cantidad de dígitos de un número es la que utiliza logaritmos. Esta versión es muy simple de implementar pero antes de ello se debe entender qué se entiende por logaritmo.

Sea b un número real positivo no nulo distinto de 1, y x otro número positivo no nulo. Se denomina logaritmo del número x en la base b, al exponente l al que debe elevarse la base b para obtener dicho número x. El logaritmo se expresa de la siguiente manera \log_bx y si \log_bx =l \leftrightarrow b^l=x . Por ejemplo \log_{5}{625}=4 ya que 625=5^4=5 \times 5 \times 5 \times 5. El logaritmo es la operación inversa a la exponenciación.

Pues bien, ¿qué tienen que ver los logaritmos con la cantidad de dígitos de un número? Pues mucho. Veamos. Supongamos que tenemos el número 123. Si le aplicamos el logaritmo en base 10, obtenemos que \log_{10}{123} \approx 2.089905111 . Esto significa que 10^{2.089905111}=123. Probemos ahora con otro número, por ejemplo 654, \log_{10}{654} \approx 2.815577748 . Esto significa que 10^{2.815577748}=654. Ahora con 1000, \log_{10}{1000} = 3 . Esto significa que 10^{3}=1000.

Lo que el logaritmo en base 10 no está retornando es a cuanto debemos elevar 10 para que retorne el número en cuestión. Cómo sabemos que estamos usando el sistema de numeración decimal, es decir, en base 10.  Básicamente lo que el logaritmo no está respondiendo es cuántas potencias de 10 yo debo multiplicar para llegar a dicho número. Pero cada vez que usamos una potencia de 10, significa que el dígito posee un dígito adicional a dicha potencia. Por ejemplo, si yo puedo representar un número con 3 potencias de 10, significará que tendrá 4 dígitos, pues 10^3=1000. Si yo puedo representar un número con  2.089905111 potencias de 10, entonces se requerirán 3 dígitos. Y es esta la razón por la cual podemos obtener la cantidad de dígitos dado el logaritmo.

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

Bonus track: cuenta dígitos en otra base

El logaritmo también se puede usar para contar la cantidad de dígitos que posee el número en otras bases. Simplemente en lugar de usar como base del logaritmo 10, usamos la base en la cual deseamos obtener la cantidad de dígitos. 

int cuenta_digitos(int numero, int base) {
    if (numero == 0)
        return 1;
    return log(numero)/log(base) + 1;
}
 

Conclusión

Hemos presentado en este artículo, 5 propuestas de solución al problema de contar dígitos de un número en 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 *