2009-02-16 18 views
33

Me temo que hay una respuesta simple y obvia a esta pregunta. Necesito determinar cuántos dígitos tiene un conteo de elementos, de modo que pueda rellenar cada número de artículo con el mínimo número de ceros iniciales necesarios para mantener la alineación. Por ejemplo, no deseo ceros a la izquierda si el total es < 10, 1 si es entre 10 y 99, etc.¿Cómo puedo contar los dígitos en un número entero sin un molde de cuerda?

Una solución sería convertir el recuento de elementos en una cadena y luego contar los caracteres. ¡Yuck! ¿Hay una mejor manera?

Editar: No hubiera pensado usar el common logarithm (no sabía que existiera tal cosa). Entonces, no es obvio, para mí, pero definitivamente simple.

+1

Aunque la solución logaritmo recibió la mayoría de votos positivos, en mi opinión la conversión de cadenas (que, sorprendentemente, se ha propuesto una sola vez) es el mejor. Refleja exactamente su intención y existe la posibilidad de que pueda escribir un componente universal que lo haga para cualquier tipo de ítem (no solo para números). –

Respuesta

51

Esto debe hacerlo:

int length = (number ==0) ? 1 : (int)Math.log10(number) + 1; 
+0

dijo que era para contar. lo que implica que el dominio está sobre los números naturales, ¿no? así que no hay necesidad de un control negativo. –

+1

La última vez que revisé, el número cero tiene un dígito, no cero. Entonces, ¿no debería el número == 0 implicar longitud = 1? –

+0

lol. duh. arreglado. –

0

Una solución es proporcionada por logaritmo en base 10, un poco excesivo.

4

Puede utilizar un bucle while, que probablemente será más rápido que un logaritmo porque esto sólo utiliza la aritmética de enteros:

int len = 0; 
while (n > 0) { 
    len++; 
    n /= 10; 
} 

lo dejo como ejercicio para el lector para ajustar este algoritmo para manejar cero y números negativos.

+0

Este es un buen compromiso. Un "registro poco entusiasta (n)". Va a ser más eficiente que convertir a cadena, ya que la conversión usa esto como parte de su algoritmo. – gbarry

+0

fyl2x es solo algo así como 20-100 ciclos. div toma alrededor de 40, por lo que solo tomará casos de 3-4 dígitos antes de que este algoritmo corra el riesgo de ser más lento que un registro. En el mejor de los casos, el registro es más rápido que un paso en este ciclo ... – jheriko

+0

@jheriko: Buen punto. Para el rendimiento en bruto, sospecho que su solución de matriz estática, o incluso una secuencia de línea en comparación con los valores inmediatos, podría ser la más rápida. Pero en realidad, ¡se está partiendo los pelos en este punto! –

0

Puede recorrer y eliminar por 10, contar el número de veces que realiza un ciclo;

int num = 423; 
int minimum = 1; 
while (num > 10) { 
    num = num/10; 
    minimum++; 
} 
12
int length = (int)Math.Log10(Math.Abs(number)) + 1; 

Es posible que necesite para tener en cuenta el signo negativo ..

+1

+1, SIN EMBARGO Esto falla cuando el número == 0. Necesitas un caso especial esto. –

4

Si va a rellenar el número en .Net, entonces

num.ToString().PadLeft(10, '0') 

podría hacer lo que quiera .

+1

Mi interpretación es que tiene una * lista * de números, y quiere rellenar los más pequeños para que coincidan con el ancho de la más grande. Por lo tanto, todavía necesita averiguar qué pasar para el primer parámetro a PadLeft. –

1

Dado que un número no tiene ceros a la izquierda, de todos modos está convirtiendo para agregarlos. No estoy seguro de por qué estás tan esforzándote por evitarlo para encontrar la longitud en la que el resultado final tendrá que ser una cadena de todos modos.

+0

Me gusta explorar soluciones alternativas. A veces aprendo cosas, como log10. – Metaphile

+0

Estoy de acuerdo en que es bueno aprender de otras maneras. Simplemente no podía ver por qué lo harías en un caso tan obvio cuando no era necesario. :-) Como dije, si sabes que el resultado final será una cadena, ¿por qué perder el tiempo trabajando para no seguir adelante y hacer la conversión y terminarlo? –

0

Está bien, no puedo resistir: utilizar /=:

#include <stdio.h> 

int 
main(){ 
     int num = 423; 
     int count = 1; 
     while(num /= 10) 
       count ++; 
     printf("Count: %d\n", count); 
     return 0; 
} 
534 $ gcc count.c && ./a.out 
Count: 3 
535 $ 
11

Una solución más eficiente que la división repetida se repetiría si las declaraciones con multiplica por ejemplo ... (Donde n es el número se requiere cuyo número de dígitos)

unsigned int test = 1; 
unsigned int digits = 0; 
while (n >= test) 
{ 
    ++digits; 
    test *= 10; 
} 

Si hay algún límite en el número de elementos (por ejemplo, la gama de 32 bits de un unsigned int), entonces una forma aún mejor superior razonable es comparar con miembros de una matriz estática, por ejemplo

// this covers the whole range of 32-bit unsigned values 
const unsigned int test[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; 

unsigned int digits = 10; 
while(n < test[digits]) --digits; 
+0

Creo que esta es la solución más clara y eficiente. Sin embargo, su matriz debería comenzar con 0, ya que 0 tiene 1 dígito. –

+0

Prácticamente, desde el punto de vista del rendimiento, la tabla de búsqueda es la mejor solución absoluta. La multiplicación es la segunda mejor solución, ya que lleva menos tiempo que las versiones de registro o de división. –

+0

Me acabo de dar cuenta de que hay un error en la versión de búsqueda. Si n es mayor o igual que 1000000000 (10 dígitos), se caerá del extremo de la matriz. –

2

Hubiera publicado un comentario pero mi puntaje de representante no me otorgará esa distinción.

Todo lo que quería señalar es que a pesar de que el Log (10) es una solución muy elegante (léase: muy pocas líneas de código), es probablemente la que más grava al procesador.

Creo que la respuesta de Jherico es probablemente la solución más eficiente y, por lo tanto, debería ser recompensada como tal.

Especialmente si usted va a estar haciendo esto por un montón de números ..

+0

gracias por la copia de seguridad, pero si la mayoría prefiere la solución de logaritmo es su elección. puede ser lento, pero es más fácil. :) – jheriko

+0

sí, estoy sorprendido de ver cuántos votaron por la solución de registro (no es que sea una terrible) – user67143

+0

Sí, ese es un buen punto para plantear, uno que creo que muchos ignoraron. ¡Y bienvenido al "club de comentarios"! ;-) – Cerebrus

Cuestiones relacionadas