Hallar la longitud de un entero en C

10 minutos de lectura

avatar de usuario
marabunta2048

Me gustaría saber cómo puedo encontrar la longitud de un número entero en C.

Por ejemplo:

  • 1 => 1
  • 25 => 2
  • 12512 => 5
  • 0 => 1

y así.

¿Cómo puedo hacer esto en C?

  • ¿Cuál es la definición de “longitud” si el número entero es 0? ¿Negativo?

    – kennytm

    18 de junio de 2010 a las 9:11

  • Consulte stackoverflow.com/questions/679602/…. Es casi un duplicado, pero no exacto, ya que es una pregunta de .NET.

    – ChrisF

    18 de junio de 2010 a las 9:36

  • la pregunta correcta no es la longitud del entero, sino cuál es el número mínimo de dígitos decimales necesarios para representar ese número (mantenido en un C int). log10 es tu amigo: log10(10000) = 4, +1 el número de dígitos (log10 debe ser truncado)… si el num es negativo, necesitas uno más para el símbolo -, si quieres contarlo, y log10(-num) (ya que el registro de un número negativo es “problemático”.

    – ShinTakezou

    18 de junio de 2010 a las 9:41

  • ¿Qué tan seguro estás de eso? log10(10000) devolverá 4 y no 3.999999…?

    –Keith Thompson

    29 de agosto de 2011 a las 5:58

  • Mmm. El experimento muestra que log10(10**n) da el valor exacto para potencias de 10 de 1 a 2**19, al menos con gcc y glibc. Pero no contaría con él para todas las implementaciones. (** denota exponenciación; no hay tal operador en C.)

    –Keith Thompson

    29 de agosto de 2011 a las 6:02

avatar de usuario
jordán lewis

C:

¿Por qué no simplemente tomar el logaritmo en base 10 del valor absoluto del número, redondearlo hacia abajo y agregar uno? Esto funciona para números positivos y negativos que no son 0 y evita tener que usar funciones de conversión de cadenas.

los log10, absy floor funciones son proporcionadas por math.h. Por ejemplo:

int nDigits = floor(log10(abs(the_integer))) + 1;

Debe envolver esto en una cláusula que asegure que the_integer != 0ya que log10(0) devoluciones -HUGE_VAL de acuerdo a man 3 log.

Además, es posible que desee agregar uno al resultado final si la entrada es negativa, si está interesado en la longitud del número, incluido su signo negativo.

Java:

int nDigits = Math.floor(Math.log10(Math.abs(the_integer))) + 1;

nótese bien La naturaleza de punto flotante de los cálculos involucrados en este método puede hacer que sea más lento que un enfoque más directo. Vea los comentarios de la respuesta de Kangkan para una discusión sobre la eficiencia.

  • En realidad, deberías usar piso y agregar 1 en su lugar. Math.Ceil(Math.Log(99)) = 2 pero Math.Ceil(Math.Log(10)) = 1. Math.Floor(Math.Log(99)) + 1 = 2 y Math.Floor(Math. Registro (10)) = 2

    – Sani Singh Huttunen

    18 de junio de 2010 a las 9:20

  • La pregunta no es del todo clara sobre la definición de longitud (por lo que posiblemente podría haber pensado en ‘número de dígitos excluyendo los ceros iniciales’), pero esperaría que 0 y -1 devuelvan 1 y 2 como la longitud de su representación de caracteres en lugar de que -2147483648 y 1.

    –Pete Kirkham

    18 de junio de 2010 a las 9:40

  • @Pete Gracias por recordarme sobre la limitación del dominio del registro y el caso del número negativo: he editado mi respuesta.

    – Jordán Lewis

    18 de junio de 2010 a las 9:51


  • +1 agradable y corto: esta es mi respuesta preferida, incluso si es la más lenta; después de todo, la diferencia de velocidad no es enorme y es muy poco probable que este tipo de código sea un rendimiento. cuello de botella de todos modos.

    – Eamon Nerbonné

    18 de junio de 2010 a las 13:20

  • Esto no funciona para 9999999999999999999, un número entero de C que se convertirá a un valor doble mayor y, por lo tanto, producirá un recuento erróneo de dígitos. El OP no especificó intsolo entero.

    – chqrlie

    23 de noviembre de 2015 a las 23:08

avatar de usuario
Eamon Nerbonne

Si estás interesado en un rápido y muy simple solución, la siguiente podría ser la más rápida (esto depende de la distribución de probabilidad de los números en cuestión):

int lenHelper(unsigned x) {
    if (x >= 1000000000) return 10;
    if (x >= 100000000)  return 9;
    if (x >= 10000000)   return 8;
    if (x >= 1000000)    return 7;
    if (x >= 100000)     return 6;
    if (x >= 10000)      return 5;
    if (x >= 1000)       return 4;
    if (x >= 100)        return 3;
    if (x >= 10)         return 2;
    return 1;
}

int printLen(int x) {
    return x < 0 ? lenHelper(-x) + 1 : lenHelper(x);
}

Si bien es posible que no gane premios por la solución más ingeniosa, es trivial de entender y también de ejecutar, por lo que es rápido.

En un Q6600 usando MSC, comparé esto con el siguiente bucle:

int res = 0;
for(int i = -2000000000; i < 2000000000; i += 200) res += printLen(i);

Esta solución tarda 0,062 s, la segunda solución más rápida de Pete Kirkham utilizando un enfoque de logaritmo inteligente tarda 0,115 s, casi el doble. Sin embargo, para números alrededor de 10000 e inferiores, el registro inteligente es más rápido.

A expensas de cierta claridad, puede superar de forma más fiable el registro inteligente (al menos, en un Q6600):

int lenHelper(unsigned x) { 
    // this is either a fun exercise in optimization 
    // or it's extremely premature optimization.
    if(x >= 100000) {
        if(x >= 10000000) {
            if(x >= 1000000000) return 10;
            if(x >= 100000000) return 9;
            return 8;
        }
        if(x >= 1000000) return 7;
        return 6;
    } else {
        if(x >= 1000) {
            if(x >= 10000) return 5;
            return 4;
        } else {
            if(x >= 100) return 3;
            if(x >= 10) return 2;
            return 1;
        }
    }
}

Esta solución sigue siendo de 0,062 s para números grandes y se degrada a alrededor de 0,09 s para números más pequeños, más rápido en ambos casos que el enfoque de registro inteligente. (gcc crea un código más rápido; 0,052 para esta solución y 0,09 s para el enfoque de registro inteligente).

  • Me estremezco al pensar cómo se vería la segunda versión escrita completamente con el operador ternario…

    – Eamon Nerbonné

    18 de junio de 2010 a las 13:22

  • Si esto se usara para masticar largas listas de números, la cantidad de código de bifurcación causaría estragos en la CPU.s branch prediction and not produce the fastest execution Itengo miedo.

    – Lloyd Crawley

    23 de octubre de 2013 a las 8:52

  • En mi punto de referencia, sigue siendo la solución más rápida: tenga en cuenta que todas las demás soluciones integrales también requieren varias ramas, y la única alternativa real es una conversión de int a doble con un registro de punto flotante (que resulta que tampoco es barato) .

    – Eamon Nerbonné

    23/10/2013 a las 16:15

  • @earthdan: esa solución está bien, pero bastante lenta debido a las divisiones. También usa siempre más ramas que la segunda versión de este código, y más en promedio que la primera solución publicada aquí. Además, esa solución es bastante inteligente (en el mal sentido) porque la razón por la que funciona no es del todo obvia. Si desea una solución breve y obvia, use stackoverflow.com/a/3068412/42921; si quieres una solución rápida y obvia, usa esto. No puedo imaginar el caso de uso de stackoverflow.com/a/6655759/2382629 (¡aunque, por supuesto, es un ejercicio intelectual divertido!)

    – Eamon Nerbonné

    17 de marzo de 2014 a las 12:55


avatar de usuario
zed_0xff

int get_int_len (int value){
  int l=1;
  while(value>9){ l++; value/=10; }
  return l;
}

y el segundo también funcionará para números negativos:

int get_int_len_with_negative_too (int value){
  int l=!value;
  while(value){ l++; value/=10; }
  return l;
}

  • Me gusta esto. No hay búferes de caracteres temporales con suposiciones sobre el tamaño.

    – Noufal Ibrahim

    18 de junio de 2010 a las 9:13

  • Rápido y elegante, sin embargo, esto no funcionará para números negativos. No sé si eso es una preocupación para el cartel de preguntas.

    – Jaime Wong

    18 de junio de 2010 a las 9:16

  • va a. darle una oportunidad. regresará 1

    – zed_0xff

    19 de junio de 2010 a las 10:10

  • Tienes razón, de hecho lo hará :-). Sería más claro para mí (y no más lento) distinguir ese caso a través de un retorno si en lugar de una negación.

    – Eamon Nerbonné

    21 de junio de 2010 a las 7:54

Puedes escribir una función como esta:

unsigned numDigits(const unsigned n) {
    if (n < 10) return 1;
    return 1 + numDigits(n / 10);
}

avatar de usuario
Fritz G Mehner

longitud de n:

length =  ( i==0 ) ? 1 : (int)log10(n)+1;

  • Probablemente debería evitar el redondeo a través de la conversión y, en su lugar, optar por un enfoque de redondeo más explícito (también conocido como portátil y consistente).

    – Chris Lutz

    18 de junio de 2010 a las 9:18

  • como es casting ¿implementado? ¿Cómo se puede implementar una función como piso? (suponemos un procesador con ieee en hardware, o a través de un coprocesador matemático, o la disponibilidad de la función de software para realizar la misma función normalmente presente en los procesadores con capacidad fp)… al final (int) es portátil y consistente en la mayoría de los casos (me atrevo a decir, todos los casos de los que normalmente nos ocupamos)

    – ShinTakezou

    18 de junio de 2010 a las 9:48

  • Como se mencionó en otras publicaciones, esto fallará cuando n = 0

    – Jaime Wong

    18 de junio de 2010 a las 9:59

  • @Lutz: ¿qué tipo de portabilidad está comprando al asumir que la conversión de doble a int no está definida? ¿Existe realmente una plataforma relevante donde este sea el caso?

    – Eamon Nerbonné

    18 de junio de 2010 a las 13:34

  • @Chris Lutz Si se trata de una implementación C compatible con los estándares, entonces obedece Cuando un valor finito de tipo flotante real se convierte en un tipo entero que no sea _Bool, la parte fraccionaria se descarta (es decir, el valor se trunca hacia cero).

    –Pete Kirkham

    18 de junio de 2010 a las 17:44

avatar de usuario
sam hocevar

un correcto snprintf implementación:

int count = snprintf(NULL, 0, "%i", x);

  • Probablemente debería evitar el redondeo a través de la conversión y, en su lugar, optar por un enfoque de redondeo más explícito (también conocido como portátil y consistente).

    – Chris Lutz

    18 de junio de 2010 a las 9:18

  • como es casting ¿implementado? ¿Cómo se puede implementar una función como piso? (suponemos un procesador con ieee en hardware, o a través de un coprocesador matemático, o la disponibilidad de la función de software para realizar la misma función normalmente presente en los procesadores con capacidad fp)… al final (int) es portátil y consistente en la mayoría de los casos (me atrevo a decir, todos los casos de los que normalmente nos ocupamos)

    – ShinTakezou

    18 de junio de 2010 a las 9:48

  • Como se mencionó en otras publicaciones, esto fallará cuando n = 0

    – Jaime Wong

    18 de junio de 2010 a las 9:59

  • @Lutz: ¿qué tipo de portabilidad está comprando al asumir que la conversión de doble a int no está definida? ¿Existe realmente una plataforma relevante donde este sea el caso?

    – Eamon Nerbonné

    18 de junio de 2010 a las 13:34

  • @Chris Lutz Si se trata de una implementación C compatible con los estándares, entonces obedece Cuando un valor finito de tipo flotante real se convierte en un tipo entero que no sea _Bool, la parte fraccionaria se descarta (es decir, el valor se trunca hacia cero).

    –Pete Kirkham

    18 de junio de 2010 a las 17:44

avatar de usuario
IVlad

El número de dígitos de un número entero x es igual a 1 + log10(x). Así que puedes hacer esto:

#include <math.h>
#include <stdio.h>

int main()
{
    int x;
    scanf("%d", &x);
    printf("x has %d digits\n", 1 + (int)log10(x));
}

O puede ejecutar un ciclo para contar los dígitos usted mismo: haga una división entera por 10 hasta que el número sea 0:

int numDigits = 0;
do
{
    ++numDigits;
    x = x / 10;
} while ( x );

Hay que tener un poco de cuidado para volver 1 si el entero es 0 en la primera solución y es posible que también desee tratar enteros negativos (trabajar con -x si x < 0).

  • Sí, un bonito y sencillo. do lazo.

    – chux – Reincorporar a Monica

    23 de noviembre de 2015 a las 23:07

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad