¿Manera de obtener el número de dígitos en un int?

¿Hay una forma más ordenada de obtener el número de dígitos en un int que este método?

int numDigits = String.valueOf(1000).length();

preguntado el 20 de agosto de 09 a las 11:08

defina la longitud de un int por favor. -

Creo que quiere contar los dígitos del número. -

Las respuestas que te da la gente son correctas ... te dan la longitud de tu int sin convertirlo en una cadena ... pero ¿por qué no quieres convertirlo en una cadena? ¿Es una cuestión de velocidad? Si es así, no estoy convencido de que estos métodos sean más rápidos ... es posible que desee hacer algunas pruebas (o decidir si es importante).

Los dígitos hexadecimales de @ptomli siguen siendo dígitos, solo que en un sistema base diferente. -

@Ptomli Seguro, pero tanto en la función Integer.toString como en la conversación general, el decimal es el valor predeterminado. Cuando el banco me dice, "Escriba el monto de su cheque en esta casilla", no les pregunto si debo escribirlo en decimal, hexadecimal u octal. Asumimos decimal a menos que se especifique lo contrario o lo solicite el contexto. -

30 Respuestas

Su solución basada en cadenas está perfectamente bien, no hay nada "desordenado" en ella. Tienes que darte cuenta de que matemáticamente los números no tienen longitud ni dígitos. La longitud y los dígitos son propiedades de un representación física de un número en una base específica, es decir, una Cadena.

Una solución basada en logaritmos hace (algunas de) las mismas cosas que la basada en cadenas hace internamente, y probablemente lo hace (insignificantemente) más rápido porque solo produce la longitud e ignora los dígitos. Pero en realidad no lo consideraría más claro en su intención, y ese es el factor más importante.

Respondido 20 ago 09, 16:08

+1 para considerar la intención del código al elegir una forma de resolver un problema - pupeño

Punto de datos: En mi máquina, el método de registro parece ejecutarse un poco menos del doble de rápido que los métodos de longitud de cadena. No llamaría eso insignificante si el método se llama mucho o en una sección de código de tiempo crítico. - CPerkins

Vea mi prueba unitaria de referencia a continuación (que también puede tener fallas, no soy un experto en pruebas de referencia). En una gran cantidad de carreras (100 000 000), la velocidad es de 11 a 8 segundos en mi máquina, apenas el doble. - Jean

@CPerkins. Optimización prematura. Conoces la perorata. - miguel borgwardt

Alguna adición (bastante tardía): es posible que no funcione correctamente para valores negativos, dependiendo de si espera que el "-" sea un dígito o no. Añadiendo Math.abs() solucionará esto, sin embargo. - Ying Yang

El logaritmo es tu amigo:

int n = 1000;
int length = (int)(Math.log10(n)+1);

NB: solo válido para n> 0.

contestado el 22 de mayo de 14 a las 21:05

¿Y es esto más rápido o mejor que usar mi variante? - primero

+1 Me ganaste por un segundo, y tu respuesta fue correcta, mientras que la mía estuvo un poco fuera de lugar. Sin embargo, tenga en cuenta que el compilador se quejará debido a que falta una conversión a int - Puñal

@Tom ¿Por qué asumirías que es caro? Se podría suponer que el coprocesador matemático lo ejecutaría, por lo que podría estar cerca de la velocidad de una suma. Incluso si java no usa el coprocesador ahora, es una buena suposición que podría ... (simplemente ignoraremos su implicación aún más inculta de que Java es lento porque probablemente no esté interesado en la evidencia, o si fueras irías a shootout.alioth.debian.org y descúbrelo por ti mismo) - Bill K

Funciona ... a menos que el valor que está comprobando = 0, lo que le dará resultados extraños (-2147483647). API Math.log10: "Si el argumento es cero positivo o cero negativo, el resultado es infinito negativo". - Mujimu

+1 Presentar un método que no implica asignaciones de memoria de objetos, lo cual es imprescindible para maximizar la reutilización y evitar las colecciones de GC. - Michael Wojcik

El enfoque más rápido: divide y vencerás.

Suponiendo que su rango es de 0 a MAX_INT, entonces tiene de 1 a 10 dígitos. Puede acercarse a este intervalo utilizando dividir y conquistar, con hasta 4 comparaciones por cada entrada. Primero, divide [1..10] en [1..5] y [6..10] con una comparación, y luego divide cada intervalo de longitud 5 usando una comparación en un intervalo de longitud 3 y un intervalo de longitud 2. El intervalo de longitud 2 requiere una comparación más (3 comparaciones en total), el intervalo de longitud 3 se puede dividir en intervalo de longitud 1 (solución) y un intervalo de longitud 2. Entonces, necesitas 3 o 4 comparaciones.

Sin divisiones, sin operaciones de coma flotante, sin logaritmos costosos, solo comparaciones de números enteros.

Código (largo pero rápido):

if (n < 100000) {
    // 5 or less
    if (n < 100){
        // 1 or 2
        if (n < 10)
            return 1;
        else
            return 2;
    } else {
        // 3 or 4 or 5
        if (n < 1000)
            return 3;
        else {
            // 4 or 5
            if (n < 10000)
                return 4;
            else
                return 5;
        }
    }
} else {
    // 6 or more
    if (n < 10000000) {
        // 6 or 7
        if (n < 1000000)
            return 6;
        else
            return 7;
    } else {
        // 8 to 10
        if (n < 100000000)
            return 8;
        else {
            // 9 or 10
            if (n < 1000000000)
                return 9;
            else
                return 10;
        }
    }
}

Benchmark (después del calentamiento de JVM): consulte el código a continuación para ver cómo se ejecutó el benchmark:

  1. método de línea de base (con String.length): 2145ms
  2. Método log10: 711 ms = 3.02 veces más rápido que la línea de base
  3. división repetida: 2797 ms = 0.77 veces más rápido que la línea de base
  4. divide y vencerás: 74 ms = 28.99
    veces más rápido que la línea de base

Código completo:

public static void main(String[] args) throws Exception {
    
    // validate methods:
    for (int i = 0; i < 1000; i++)
        if (method1(i) != method2(i))
            System.out.println(i);
    for (int i = 0; i < 1000; i++)
        if (method1(i) != method3(i))
            System.out.println(i + " " + method1(i) + " " + method3(i));
    for (int i = 333; i < 2000000000; i += 1000)
        if (method1(i) != method3(i))
            System.out.println(i + " " + method1(i) + " " + method3(i));
    for (int i = 0; i < 1000; i++)
        if (method1(i) != method4(i))
            System.out.println(i + " " + method1(i) + " " + method4(i));
    for (int i = 333; i < 2000000000; i += 1000)
        if (method1(i) != method4(i))
            System.out.println(i + " " + method1(i) + " " + method4(i));
    
    // work-up the JVM - make sure everything will be run in hot-spot mode
    allMethod1();
    allMethod2();
    allMethod3();
    allMethod4();
    
    // run benchmark
    Chronometer c;
    
    c = new Chronometer(true);
    allMethod1();
    c.stop();
    long baseline = c.getValue();
    System.out.println(c);
    
    c = new Chronometer(true);
    allMethod2();
    c.stop();
    System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times as fast as baseline");
    
    c = new Chronometer(true);
    allMethod3();
    c.stop();
    System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times as fast as baseline");
    
    c = new Chronometer(true);
    allMethod4();
    c.stop();
    System.out.println(c + " = " + StringTools.formatDouble((double)baseline / c.getValue() , "0.00") + " times as fast as baseline");
}


private static int method1(int n) {
    return Integer.toString(n).length();
}

private static int method2(int n) {
    if (n == 0)
        return 1;
    return (int)(Math.log10(n) + 1);
}

private static int method3(int n) {
    if (n == 0)
        return 1;
    int l;
    for (l = 0 ; n > 0 ;++l)
        n /= 10;
    return l;
}

private static int method4(int n) {
    if (n < 100000) {
        // 5 or less
        if (n < 100) {
            // 1 or 2
            if (n < 10)
                return 1;
            else
                return 2;
        } else {
            // 3 or 4 or 5
            if (n < 1000)
                return 3;
            else {
                // 4 or 5
                if (n < 10000)
                    return 4;
                else
                    return 5;
            }
        }
    } else {
        // 6 or more
        if (n < 10000000) {
            // 6 or 7
            if (n < 1000000)
                return 6;
            else
                return 7;
        } else {
            // 8 to 10
            if (n < 100000000)
                return 8;
            else {
                // 9 or 10
                if (n < 1000000000)
                    return 9;
                else
                    return 10;
            }
        }
    }
}


private static int allMethod1() {
    int x = 0;
    for (int i = 0; i < 1000; i++)
        x = method1(i);
    for (int i = 1000; i < 100000; i += 10)
        x = method1(i);
    for (int i = 100000; i < 1000000; i += 100)
        x = method1(i);
    for (int i = 1000000; i < 2000000000; i += 200)
        x = method1(i);
    
    return x;
}

private static int allMethod2() {
    int x = 0;
    for (int i = 0; i < 1000; i++)
        x = method2(i);
    for (int i = 1000; i < 100000; i += 10)
        x = method2(i);
    for (int i = 100000; i < 1000000; i += 100)
        x = method2(i);
    for (int i = 1000000; i < 2000000000; i += 200)
        x = method2(i);
    
    return x;
}

private static int allMethod3() {
    int x = 0;
    for (int i = 0; i < 1000; i++)
        x = method3(i);
    for (int i = 1000; i < 100000; i += 10)
        x = method3(i);
    for (int i = 100000; i < 1000000; i += 100)
        x = method3(i);
    for (int i = 1000000; i < 2000000000; i += 200)
        x = method3(i);
    
    return x;
}

private static int allMethod4() {
    int x = 0;
    for (int i = 0; i < 1000; i++)
        x = method4(i);
    for (int i = 1000; i < 100000; i += 10)
        x = method4(i);
    for (int i = 100000; i < 1000000; i += 100)
        x = method4(i);
    for (int i = 1000000; i < 2000000000; i += 200)
        x = method4(i);
    
    return x;
}

Nuevamente, punto de referencia:

  1. método de línea de base (con String.length): 2145ms
  2. Método log10: 711 ms = 3.02 veces más rápido que la línea de base
  3. división repetida: 2797 ms = 0.77 veces más rápido que la línea de base
  4. divide y vencerás: 74 ms = 28.99 veces más rápido que la línea de base

Editar

Después de escribir el punto de referencia, eché un vistazo a Integer.toString de Java 6 y descubrí que usa:

final static int [] sizeTable = { 9, 99, 999, 9999, 99999, 999999, 9999999,
                                  99999999, 999999999, Integer.MAX_VALUE };

// Requires positive x
static int stringSize(int x) {
    for (int i=0; ; i++)
        if (x <= sizeTable[i])
            return i+1;
}

Lo comparé con mi solución de divide y vencerás:

  1. divide y vencerás: 104 ms
  2. Solución Java 6 - iterar y comparar: 406ms

El mío es aproximadamente 4 veces más rápido que la solución Java 6.

Respondido el 16 de enero de 21 a las 05:01

esto se ve muy bien. podría escribirlo un poco más compacto usando el operador?: para obtener más aceptación - André Pareis

hablar de optimización prematura: D - gordon gustafson

Me gusta! ¿Qué tal un bloque de interruptores en lugar de if-elseses tan anidados? - Kebman

No me di cuenta de que todas estas declaraciones if else serían TAN mucho más rápidas que convertir el int a String y luego llamar a .length. +1 - Ojos

Usando el operador ternario, lo reduce a 101 caracteres: n<100000?n<100?n<10?1:2:n<1000?3:n<10000?4:5:n<10000000?n<1000000?6:7:n<100000000?8:n<1000000000?9:10 - jonathan gawrych

Dos comentarios sobre su punto de referencia: Java es un entorno complejo, con compilación justo a tiempo y recolección de basura, etc., así que para obtener una comparación justa, cada vez que ejecuto un punto de referencia, siempre: (a) adjunto las dos pruebas en un bucle que los ejecuta en secuencia 5 o 10 veces. Muy a menudo, el tiempo de ejecución en el segundo paso a través del bucle es bastante diferente del primero. Y (b) Después de cada "enfoque", hago un System.gc () para intentar activar una recolección de basura. De lo contrario, el primer enfoque podría generar un montón de objetos, pero no lo suficiente como para forzar una recolección de basura, luego el segundo enfoque crea algunos objetos, el montón se agota y la recolección de basura se ejecuta. Luego, el segundo enfoque se "cobra" por recoger la basura dejada por el primer enfoque. ¡Muy injusto!

Dicho esto, ninguno de los anteriores marcó una diferencia significativa en este ejemplo.

Con o sin esas modificaciones, obtuve resultados muy diferentes a los tuyos. Cuando ejecuté esto, sí, el enfoque toString dio tiempos de ejecución de 6400 a 6600 milis, mientras que el enfoque de registro fue de 20,000 a 20,400 milis. En lugar de ser un poco más rápido, el enfoque de registro fue 3 veces más lento para mí.

Tenga en cuenta que los dos enfoques implican costos muy diferentes, por lo que esto no es del todo impactante: el enfoque toString creará una gran cantidad de objetos temporales que deben limpiarse, mientras que el enfoque de registro requiere un cálculo más intenso. Entonces, tal vez la diferencia es que en una máquina con menos memoria, toString requiere más rondas de recolección de basura, mientras que en una máquina con un procesador más lento, el cálculo adicional de log sería más doloroso.

También probé un tercer enfoque. Escribí esta pequeña función:

static int numlength(int n)
{
    if (n == 0) return 1;
    int l;
    n=Math.abs(n);
    for (l=0;n>0;++l)
        n/=10;
    return l;           
}

Eso se ejecutó en 1600 a 1900 milis, menos de 1/3 del enfoque toString y 1/10 del enfoque de registro en mi máquina.

Si tuvieras un rango amplio de números, podrías acelerarlo aún más al comenzar dividiendo por 1,000 o 1,000,000 para reducir el número de veces a través del ciclo. No he jugado con eso.

Respondido 05 Oct 16, 18:10

¿Ha intentado variar la entrada? De lo contrario, la máquina virtual del punto de acceso podría optimizar este gráfico, lo que da como resultado puntos de referencia incorrectos, porque devuelve lo mismo precalculado cada vez. - erik aigner

Tenga en cuenta que Math.abs() no funciona para Integer.MIN_VALUE, y el método devolverá 0 en ese caso. - no mate

Usando Java

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

utilizan el import java.lang.Math.*; al principio

Usando C

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

utilizan el inclue math.h al principio

Respondido 29 Oct 16, 19:10

Solo para su información, resultará en infinito si the_integer is 0, así que verifique eso. - erik aigner

Tenga en cuenta que Math.abs() no funciona para Integer.MIN_VALUE. - no mate

¿Por qué piso? Creo que no es necesario, ¿podría explicarlo ?, incluso con el +1 que se requiere para obtener el recuento de dígitos real, creo que el piso es innecesario. - PerracoLabs

No puedo dejar un comentario todavía, así que lo publicaré como una respuesta separada.

La solución basada en logaritmos no calcula el número correcto de dígitos para enteros muy grandes, por ejemplo:

long n = 99999999999999999L;

// correct answer: 17
int numberOfDigits = String.valueOf(n).length();

// incorrect answer: 18
int wrongNumberOfDigits = (int) (Math.log10(n) + 1); 

La solución basada en logaritmos calcula el número incorrecto de dígitos en números enteros grandes

contestado el 23 de mayo de 17 a las 13:05

try (int) (Math.log10 (n + j)) en lugar de donde j es 10 - (n - n / 10 * 10). - erick piedra

Dado que el número de dígitos en base 10 de un entero es solo 1 + truncar (log10 (número)), tu puedes hacer:

public class Test {

    public static void main(String[] args) {

        final int number = 1234;
        final int digits = 1 + (int)Math.floor(Math.log10(number));

        System.out.println(digits);
    }
}

Editado porque mi última edición corrigió el ejemplo de código, pero no la descripción.

Respondido 20 ago 09, 16:08

Fresco. pero creo que necesita abs (número) y también "0" es un caso especial también? - DmitryK

Si. Si necesita dar cuenta del letrero, tendrá que hacer algo como 1 + (int) Math.floor (Math.log10 (Math.abs (número))) + ((número <0)? 1: 0) - Puñal

La Math.floor es un poco redundante, ¿no? Casting a int lo redondeará hacia abajo de todos modos. - computachip

@DmitryK @Dirk: Tenga en cuenta que Math.abs() no funciona para Integer.MIN_VALUE. - no mate

La solución de Marian adaptada para Corto escriba números (hasta 9,223,372,036,854,775,807), en caso de que alguien quiera copiarlo y pegarlo. En el programa escribí esto para números hasta 10000 que eran mucho más probables, así que hice una rama específica para ellos. De todos modos, no hará una diferencia significativa.

public static int numberOfDigits (long n) {     
    // Guessing 4 digit numbers will be more probable.
    // They are set in the first branch.
    if (n < 10000L) { // from 1 to 4
        if (n < 100L) { // 1 or 2
            if (n < 10L) {
                return 1;
            } else {
                return 2;
            }
        } else { // 3 or 4
            if (n < 1000L) {
                return 3;
            } else {
                return 4;
            }
        }           
    } else  { // from 5 a 20 (albeit longs can't have more than 18 or 19)
        if (n < 1000000000000L) { // from 5 to 12
            if (n < 100000000L) { // from 5 to 8
                if (n < 1000000L) { // 5 or 6
                    if (n < 100000L) {
                        return 5;
                    } else {
                        return 6;
                    }
                } else { // 7 u 8
                    if (n < 10000000L) {
                        return 7;
                    } else {
                        return 8;
                    }
                }
            } else { // from 9 to 12
                if (n < 10000000000L) { // 9 or 10
                    if (n < 1000000000L) {
                        return 9;
                    } else {
                        return 10;
                    }
                } else { // 11 or 12
                    if (n < 100000000000L) {
                        return 11;
                    } else {
                        return 12;
                    }
                }
            }
        } else { // from 13 to ... (18 or 20)
            if (n < 10000000000000000L) { // from 13 to 16
                if (n < 100000000000000L) { // 13 or 14
                    if (n < 10000000000000L) { 
                        return 13;
                    } else {
                        return 14;
                    }
                } else { // 15 or 16
                    if (n < 1000000000000000L) {
                        return 15;
                    } else {
                        return 16;
                    }
                }
            } else { // from 17 to ...¿20?
                if (n < 1000000000000000000L) { // 17 or 18
                    if (n < 100000000000000000L) {
                        return 17;
                    } else {
                        return 18;
                    }
                } else { // 19? Can it be?
                    // 10000000000000000000L is'nt a valid long.
                    return 19;
                }
            }
        }
    }
}

respondido 01 mar '12, 09:03

¿Debería cambiarse el título de esta pregunta a "Forma de obtener el número de dígitos en un int / long?" (y agregó la etiqueta 'larga') - CELDA

Otro enfoque de cuerdas. Corto y dulce: para cualquier número entero n.

int length = ("" + n).length();

Respondido el 04 de Septiembre de 18 a las 22:09

Solo funciona para números enteros positivos n y cero. Puedo usar ("" + Math.abs(n)).length() para obtener la longitud del entero negativo. - EsteClark

Tenga en cuenta que Math.abs() no funciona para Integer.MIN_VALUE. - no mate

¿Puedo intentar? ;)

basado en la solución de Dirk

final int digits = number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number))));

Respondido 20 ago 09, 16:08

Tenga en cuenta que Math.abs() no funciona para Integer.MIN_VALUE. - no mate

¿Qué hay de las viejas matemáticas simples? Dividir por 10 hasta llegar a 0.

public static int getSize(long number) {
        int count = 0;
        while (number > 0) {
            count += 1;
            number = (number / 10);
        }
        return count;
    }

Respondido 09 Oct 12, 19:10

¿Lo has probado? Sabes que, aunque tenga sentido para un punto de vista humano, en realidad no funciona igual con la "forma de pensar" de la máquina, ¿verdad? --- Permítanme proponer una cosa: haga una matriz de dos millones de números, preferiblemente Long.MAX_VALUE, que es el peor caso de complejidad de su código, y utilice System.nanoTime() para hacer una prueba de cronometraje contra los casos de peor complejidad de la otra solución. ++ En realidad, pruébelo con una matriz llena por un aleatorizador establecido en el rango de 0 a Long.MAX_VALUEtambién, solo para las pruebas de "complejidad promedio" ++ Puede que los resultados sean muy impactantes. - xenoro

@thelima Esto no funciona correctamente para cero o negativos, pero es un error menor. El principio me parece correcto. ¿A qué resultado "impactante" se refiere? - arrendajo

Digamos que las computadoras ... Bueno ... No les gusta dividir. Y en los casos en los que es necesario procesar grandes "colas" de grandes números, y cada dígito de cada número procesado requerirá una división ... Bueno ... Las cosas "empiezan a ponerse muy lentas, muy rápido" ... Si captas mi significado ... --- Es por eso que ve muchas de las respuestas aquí usando códigos basados ​​en pruebas y comparaciones con cada dígito decimal usando 'si, en lugar de divisiones: si no es más rápido, al menos mantiene la mayor parte de su velocidad independientemente de sus peores casos. --- Haz una prueba entre el uso de divisiones y logaritmos en números grandes ... - xenoro

@TheLima ¿de qué estás hablando? Por un int, este ciclo se ejecuta un máximo de 11 veces. ¿Tiene alguna evidencia para sus afirmaciones? - user207421

@EJP Desde el punto de vista del hardware, la división es un proceso iterativo. El algoritmo de división más rápido que conozco es radix4, que genera 4 bits por iteración; por lo que una división de 32 bits necesita al menos 8 iteraciones. Las multiplicaciones, por ejemplo, se pueden hacer en paralelo y también se pueden dividir en multiplicaciones más simples; ya sea hasta el nivel de bits (requiriendo solo 5 operaciones), o con un desglose parcial más una tabla de búsqueda al final (compensación de velocidad VS de tamaño clásico). No se trata solo de "cuántas iteraciones"; el problema con las divisiones radica en "lo que cada iteración implica / hace, a nivel de hardware" - xenoro

Solución de Marian, ahora con Ternary:

 public int len(int n){
        return (n<100000)?((n<100)?((n<10)?1:2):(n<1000)?3:((n<10000)?4:5)):((n<10000000)?((n<1000000)?6:7):((n<100000000)?8:((n<1000000000)?9:10)));
    }

Gracias podemos.

Respondido 01 Jul 13, 14:07

Eso es un poco difícil de leer. Tal vez agregue algunos espacios y / o nuevas líneas. - michaelb958 - GoFundMonica

¡Pero maldita sea es portátil! - rodolfo trevor

Curioso, intenté compararlo ...

import org.junit.Test;
import static org.junit.Assert.*;


public class TestStack1306727 {

    @Test
    public void bench(){
        int number=1000;
        int a= String.valueOf(number).length();
        int b= 1 + (int)Math.floor(Math.log10(number));

        assertEquals(a,b);
        int i=0;
        int s=0;
        long startTime = System.currentTimeMillis();
        for(i=0, s=0; i< 100000000; i++){
            a= String.valueOf(number).length();
            s+=a;
        }
        long stopTime = System.currentTimeMillis();
        long runTime = stopTime - startTime;
        System.out.println("Run time 1: " + runTime);
        System.out.println("s: "+s);
        startTime = System.currentTimeMillis();
        for(i=0,s=0; i< 100000000; i++){
            b= number==0?1:(1 + (int)Math.floor(Math.log10(Math.abs(number))));
            s+=b;
        }
        stopTime = System.currentTimeMillis();
        runTime = stopTime - startTime;
        System.out.println("Run time 2: " + runTime);
        System.out.println("s: "+s);
        assertEquals(a,b);


    }
}

los resultados son:

Tiempo de ejecución 1: 6765 s: 400000000 Tiempo de ejecución 2: 6000 s: 400000000

Ahora me pregunto si mi punto de referencia realmente significa algo, pero obtengo resultados consistentes (variaciones en un ms) en múltiples ejecuciones del punto de referencia en sí ... :) Parece que es inútil intentar optimizar esto ...


editar: siguiendo el comentario de ptomli, reemplacé 'número' por 'i' en el código anterior y obtuve los siguientes resultados en 5 ejecuciones del banco:

Tiempo de ejecución 1: 11500 s: 788888890 Tiempo de ejecución 2: 8547 s: 788888890 Tiempo de ejecución 1: 11485 s: 788888890 Tiempo de ejecución 2: 8547 s: 788888890 Tiempo de ejecución 1: 11469 s: 788888890 Tiempo de ejecución 2: 8547 s: 788888890 Tiempo de ejecución 1: 11500 s: 788888890 Tiempo de ejecución 2: 8547 s: 788888890 Tiempo de ejecución 1: 11484 s: 788888890 Tiempo de ejecución 2: 8547 s: 788888890

Respondido 20 ago 09, 16:08

Solo por el gusto de hacerlo, ¿cuál es la diferencia en una distribución de valores de número, digamos de 0 a un billón? :) - ptomli

Con diseño (basado en problema). Esta es una alternativa de divide y vencerás. Primero definiremos una enumeración (considerando que es solo para un int sin firmar).

public enum IntegerLength {
    One((byte)1,10),
    Two((byte)2,100),
    Three((byte)3,1000),
    Four((byte)4,10000),
    Five((byte)5,100000),
    Six((byte)6,1000000),
    Seven((byte)7,10000000),
    Eight((byte)8,100000000),
    Nine((byte)9,1000000000);

    byte length;
    int value;

    IntegerLength(byte len,int value) {
        this.length = len;
        this.value = value;
    }

    public byte getLenght() {
        return length;
    }

    public int getValue() {
        return value;
    }
}

Ahora definiremos una clase que pasa por los valores de la enumeración y compararemos y devolveremos la longitud adecuada.

public class IntegerLenght {
    public static byte calculateIntLenght(int num) {    
        for(IntegerLength v : IntegerLength.values()) {
            if(num < v.getValue()){
                return v.getLenght();
            }
        }
        return 0;
    }
}

El tiempo de ejecución de esta solución es el mismo que el del método divide y vencerás.

Respondido el 02 de diciembre de 15 a las 15:12

Un dividir y conquistar comenzaría en el medio y dividiría en dos el área de búsqueda restante. Tiene un tiempo de ejecución lineal. Pero no importará por solo 9 comparaciones. ¿Pero no se estropeará esto si num>=Nine.getValue()? - Tipi

sin API de cadena, sin utilidades, sin conversión de tipo, solo iteración java pura ->

public static int getNumberOfDigits(int input) {
    int numOfDigits = 1;
    int base = 1;
    while (input >= base * 10) {
        base = base * 10;
        numOfDigits++;
    }
    return numOfDigits;
 }

Puede buscar valores más grandes si lo desea.

Respondido el 01 de junio de 20 a las 15:06

Esto se repetirá indefinidamente para todos los valores mayores que 1874919423. Para ver por qué, intente lo siguiente: for (int x = 1, i = 0; i < 32; ++i) { System.out.println(x *= 10); } - no mate

¿Qué pasa con este método recursivo?

    private static int length = 0;

    public static int length(int n) {
    length++;
    if((n / 10) < 10) {
        length++;
    } else {
        length(n / 10);
    }
    return length;
}

Respondido el 20 de diciembre de 12 a las 14:12

Solución simple:

public class long_length {
    long x,l=1,n;
    for (n=10;n<x;n*=10){
        if (x/n!=0){
            l++;
        }
    }
    System.out.print(l);
}

respondido 29 mar '13, 23:03

Una solución realmente simple:

public int numLength(int n) {
  for (int length = 1; n % Math.pow(10, length) != n; length++) {}
  return length;
}

Respondido 23 ago 14, 23:08

No llamaría simple una línea por bucle con un cuerpo vacío. Ni módulo una potencia de 10 para ver si recuperas lo mismo (¿no puedes usar una comparación?). - Tipi

O en su lugar, puede verificar la longitud si el número es mayor o menor que el número deseado.

    public void createCard(int cardNumber, int cardStatus, int customerId) throws SQLException {
    if(cardDao.checkIfCardExists(cardNumber) == false) {
        if(cardDao.createCard(cardNumber, cardStatus, customerId) == true) {
            System.out.println("Card created successfully");
        } else {

        }
    } else {
        System.out.println("Card already exists, try with another Card Number");
        do {
            System.out.println("Enter your new Card Number: ");
            scan = new Scanner(System.in);
            int inputCardNumber = scan.nextInt();
            cardNumber = inputCardNumber;
        } while(cardNumber < 95000000);
        cardDao.createCard(cardNumber, cardStatus, customerId);
    }
}

}

Respondido el 09 de junio de 15 a las 15:06

No entiendo. Parece que estás respondiendo a una pregunta diferente. - Tipi

Todavía no he visto una solución basada en la multiplicación. Las soluciones de logaritmo, división y basadas en cadenas se volverán bastante difíciles de manejar frente a millones de casos de prueba, así que aquí hay una para ints:

/**
 * Returns the number of digits needed to represents an {@code int} value in 
 * the given radix, disregarding any sign.
 */
public static int len(int n, int radix) {
    radixCheck(radix); 
    // if you want to establish some limitation other than radix > 2
    n = Math.abs(n);

    int len = 1;
    long min = radix - 1;

    while (n > min) {
        n -= min;
        min *= radix;
        len++;
    }

    return len;
}

En base 10, esto funciona porque n se compara esencialmente con 9, 99, 999 ... ya que min es 9, 90, 900 ... y n se resta por 9, 90, 900 ...

Desafortunadamente, esto no es portátil para long simplemente reemplazando cada instancia de int debido al desbordamiento. Por otro lado, da la casualidad de que seguirá funciona para las bases 2 y 10 (pero falla gravemente para la mayoría de las otras bases). Necesitará una tabla de búsqueda para los puntos de desbordamiento (o una prueba de división ... ew)

/**
 * For radices 2 &le r &le Character.MAX_VALUE (36)
 */
private static long[] overflowpt = {-1, -1, 4611686018427387904L,
    8105110306037952534L, 3458764513820540928L, 5960464477539062500L,
    3948651115268014080L, 3351275184499704042L, 8070450532247928832L,
    1200757082375992968L, 9000000000000000000L, 5054470284992937710L,
    2033726847845400576L, 7984999310198158092L, 2022385242251558912L,
    6130514465332031250L, 1080863910568919040L, 2694045224950414864L,
    6371827248895377408L, 756953702320627062L, 1556480000000000000L,
    3089447554782389220L, 5939011215544737792L, 482121737504447062L,
    839967991029301248L, 1430511474609375000L, 2385723916542054400L,
    3902460517721977146L, 6269893157408735232L, 341614273439763212L,
    513726300000000000L, 762254306892144930L, 1116892707587883008L,
    1617347408439258144L, 2316231840055068672L, 3282671350683593750L,
    4606759634479349760L};

public static int len(long n, int radix) {
    radixCheck(radix);
    n = abs(n);

    int len = 1;
    long min = radix - 1;
    while (n > min) {
        len++;
        if (min == overflowpt[radix]) break;
        n -= min;
        min *= radix;

    }

    return len;
}

Respondido el 10 de junio de 15 a las 14:06

Uno quiere hacer esto principalmente porque quiere "presentarlo", lo que significa que finalmente necesita ser "toString-ed" (o transformado de otra manera) explícita o implícitamente de todos modos; antes de que pueda ser presentado (impreso, por ejemplo).

Si ese es el caso, intente hacer explícito el "toString" necesario y cuente los bits.

Respondido 03 ago 16, 04:08

Podemos lograr esto usando un bucle recursivo

    public static int digitCount(int numberInput, int i) {
        while (numberInput > 0) {
        i++;
        numberInput = numberInput / 10;
        digitCount(numberInput, i);
        }
        return i;
    }

    public static void printString() {
        int numberInput = 1234567;
        int digitCount = digitCount(numberInput, 0);

        System.out.println("Count of digit in ["+numberInput+"] is ["+digitCount+"]");
    }

Respondido 21 Abr '17, 06:04

Escribí esta función después de mirar Integer.java código fuente.

private static int stringSize(int x) {
    final int[] sizeTable = {9, 99, 999, 9_999, 99_999, 999_999, 9_999_999,
            99_999_999, 999_999_999, Integer.MAX_VALUE};
    for (int i = 0; ; ++i) {
        if (x <= sizeTable[i]) {
            return i + 1;
        }
    }
}

Respondido 20 ago 19, 03:08

Veo gente usando bibliotecas String o incluso usando la clase Integer. No hay nada de malo en eso, pero el algoritmo para obtener el número de dígitos no es tan complicado. Estoy usando un long en este ejemplo, pero funciona igual de bien con un int.

 private static int getLength(long num) {

    int count = 1;

    while (num >= 10) {
        num = num / 10;
        count++;
    }

    return count;
}

Respondido 08 Abr '20, 05:04

    int num = 02300;
    int count = 0;
    while(num>0){
         if(num == 0) break;
         num=num/10;
         count++;
    }
    System.out.println(count);

respondido 10 nov., 14:08

Sinista publicó por primera vez una solución de "dividir entre 10" dos años antes. - Tipi

Manera recursiva fácil

int    get_int_lenght(current_lenght, value)
{
 if (value / 10 < 10)
    return (current_lenght + 1);
return (get_int_lenght(current_lenght + 1, value))
}

no probado

Respondido el 02 de diciembre de 15 a las 15:12

Probablemente debería probarlo entonces (y asegurarse de que sea Java válido y esté formateado correctamente). Pero hace 10 años Jedi Dula publicó un enfoque recursivo de "dividir entre 3". - Tipi

Podrías usar los dígitos usando una división sucesiva por diez:

int a=0;

if (no < 0) {
    no = -no;
} else if (no == 0) {
    no = 1;
}

while (no > 0) {
    no = no / 10;
    a++;
}

System.out.println("Number of digits in given number is: "+a);

Respondido el 09 de Septiembre de 15 a las 13:09

Un enfoque de "dividir por 10" fue publicado por primera vez por Sinista hace 3 años. Esa es la única razón por la que puedo pensar en que obtuviste un voto negativo. - Tipi

Ingrese el número y cree un Arraylist, y el ciclo while registrará todos los dígitos en el Arraylist. Luego, podemos sacar el tamaño de la matriz, que será la longitud del valor entero que ingresó.

ArrayList<Integer> a=new ArrayList<>();

while(number > 0) 
{ 
    remainder = num % 10; 
    a.add(remainder);
    number = number / 10; 
} 

int m=a.size();

Respondido el 02 de diciembre de 15 a las 15:12

Excepto que no necesita ArrayList ni los dígitos. - user207421

Aquí hay un método realmente simple que hice que funciona para cualquier número:

public static int numberLength(int userNumber) {

    int numberCounter = 10;
    boolean condition = true;
    int digitLength = 1;

    while (condition) {
        int numberRatio = userNumber / numberCounter;
        if (numberRatio < 1) {
            condition = false;
        } else {
            digitLength++;
            numberCounter *= 10;
        }
    }

    return digitLength; 
}

La forma en que funciona con la variable del contador de números es que 10 = espacio de 1 dígito. Por ejemplo .1 = 1 décimo => espacio de 1 dígito. Por tanto, si tienes int number = 103342; obtendrá 6, porque es el equivalente a .000001 espacios atrás. Además, ¿alguien tiene un nombre de variable mejor para numberCounter? No puedo pensar en nada mejor.

Editar: Solo pensé en una mejor explicación. Básicamente, lo que hace este bucle while es dividir el número entre 10, hasta que sea menos de uno. Básicamente, cuando divide algo entre 10, lo mueve hacia atrás un espacio numérico, por lo que simplemente lo divide por 10 hasta que llegue a <1 para la cantidad de dígitos de su número.

Aquí hay otra versión que puede contar la cantidad de números en un decimal:

public static int repeatingLength(double decimalNumber) {

    int numberCounter = 1;
    boolean condition = true;
    int digitLength = 1;

    while (condition) {
        double numberRatio = decimalNumber * numberCounter;

        if ((numberRatio - Math.round(numberRatio)) < 0.0000001) {
            condition = false;
        } else {
            digitLength++;
            numberCounter *= 10;
        }
    }
    return digitLength - 1;
}

Respondido el 02 de diciembre de 15 a las 15:12

Intente convertir el int a una cadena y luego obtener la longitud del cadena. Eso debería tener la longitud del int.

public static int intLength(int num){
    String n = Integer.toString(num);
    int newNum = n.length();
    return newNum;
}

Respondido 18 Oct 15, 01:10

Esto es completamente equivalente al código original. Y extrañaré cuando number es negativo. - Tipi

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.