Manera eficiente de determinar el número de dígitos en un entero


145

¿Cuál es una forma muy eficiente de determinar cuántos dígitos hay en un entero en C ++?


11
¿En que base? 2? 10?
Jacob Krall

2
Me gustaría hacerlo en la base 10
Seth

1
Una vez hice una pregunta relacionada: ¿Cómo puedes obtener el primer dígito en un int? Muchas de las mismas metodologías que a continuación se utilizaron en las respuestas de las personas. Aquí está el enlace en caso de que sea relevante para su tarea [ stackoverflow.com/questions/701322/]
Dinah

¿El montaje en línea califica?
György Andrasek

1
Si bien todas estas respuestas están en términos de base 10, es bastante fácil de cambiar para calcular el resultado para cualquier base deseada.
Ira Baxter

Respuestas:


106

Bueno, la forma más eficiente, suponiendo que conozca el tamaño del número entero, sería una búsqueda. Debería ser más rápido que el enfoque basado en el logaritmo mucho más corto. Si no le importa contar el '-', elimine el + 1.

// generic solution
template <class T>
int numDigits(T number)
{
    int digits = 0;
    if (number < 0) digits = 1; // remove this line if '-' counts as a digit
    while (number) {
        number /= 10;
        digits++;
    }
    return digits;
}

// partial specialization optimization for 32-bit numbers
template<>
int numDigits(int32_t x)
{
    if (x == MIN_INT) return 10 + 1;
    if (x < 0) return numDigits(-x) + 1;

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

// partial-specialization optimization for 8-bit numbers
template <>
int numDigits(char n)
{
    // if you have the time, replace this with a static initialization to avoid
    // the initial overhead & unnecessary branch
    static char x[256] = {0};
    if (x[0] == 0) {
        for (char c = 1; c != 0; c++)
            x[c] = numDigits((int32_t)c);
        x[0] = 1;
    }
    return x[n];
}

55
Probablemente más rápido que mi respuesta, bien hecho. Para mayor eficiencia, si sabe que sus números de entrada serán en su mayoría pequeños (supongo que menos de 100,000), entonces invierta las pruebas: si (x <10) devuelve 1; si (x <100) devuelve 2; etc., para que la función haga menos pruebas y salga más rápido.
squelart

29
O quizás reordene y anide las declaraciones if, para hacer una búsqueda binaria en lugar de una búsqueda lineal.
dave4420

1
Esa no es una buena idea. Qué sucede cuando la arquitectura se expande a enteros de 256 bits. Debe recordar volver y modificar este código. En la vida real, eso no sucederá y, probablemente, esto se usará para construir un búfer del tamaño correcto, ahora se está abriendo a todo tipo de problemas de búfer por ejecución en arquitecturas más grandes.
Martin York

3
suponiendo una distribución uniforme de números, la búsqueda lineal inversa (comenzando desde los dígitos máximos hasta 1) puede ser más rápida en promedio que la búsqueda binaria, ya que hay muchos más números con N dígitos que con N-1 dígitos graphics.stanford.edu/~ seander / ...
fa.

66
No me preocuparía mucho por los enteros de 256 o 128 bits. A menos que necesite contar la cantidad de electrones en el Universo (10 ^ 78 la última vez que lo hice), 64 bits funcionarán bastante bien. Las máquinas de 32 bits duraron ~~ 15 años. Supongo que las máquinas de 64 bits durarán mucho más. Para un número mayor, la aritmética de multiprecisión estará bien, y dudo si la eficiencia del cómputo de dígitos computacionales será importante.
Ira Baxter

74

La forma más simple es hacer:

unsigned GetNumberOfDigits (unsigned i)
{
    return i > 0 ? (int) log10 ((double) i) + 1 : 1;
}

log10 se define en <cmath>o <math.h>. Debería hacer un perfil de esto para ver si es más rápido que cualquiera de los otros publicados aquí. No estoy seguro de cuán robusto es esto con respecto a la precisión de punto flotante. Además, el argumento no está firmado como valores negativos y el registro no se mezcla realmente.


77
Para entradas de 32 bits y flotantes de 56 bits, esto probablemente funcione. Si la entrada es larga (64 bits), los 56 bits del registro de doble precisión pueden hacer que esto produzca la respuesta incorrecta en casos de valores cercanos a valores grandes de 10 ^ n. Espere problemas por encima de 2 ^ 50.
Ira Baxter

1
También está la cuestión de cuán precisas son las funciones de registro. No he comprobado cuán precisos son en las bibliotecas modernas, y no me sentiría cómodo confiando ciegamente en que sean buenos para una parte en mil millones.
David Thornley

@DavidThornley: log u otras funciones matemáticas son perfectamente precisas a menos que se especifique en la línea de comandos del compilador. algunos se convertirán a intrínsecos x86 en tiempo de compilación. algunos no existen y se expandirán en fórmulas de intrínsecos existentes. Por ejemplo, si se usa, -fpfastse puede ver el uso de SSE Instrinsics en lugar de x87, lo que ofrece menos garantía en la precisión IIRC. pero por defecto no hay problema.
v.oddou

@DavidThornley: es más que precisión. La pregunta es si está garantizado o no ese log10 (10 ^ k) ≥ k para todos los k relevantes. Es decir, se garantiza que cualquier error de redondeo inevitable vaya en la dirección correcta. k + eps como resultado funciona, k - eps no. Y "Perfectamente preciso" es ingenuo.
gnasher729

1
La prueba i> 0 podría optimizarse para i> 9
Pat

60

Quizás entendí mal la pregunta, pero ¿no es así?

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

29
Y no me sorprendería si esta solución fuera la más rápida.
VisioN

32
int digits = 0; while (number != 0) { number /= 10; digits++; }

Nota: "0" tendrá 0 dígitos! Si necesita que 0 parezca tener 1 dígito, use:

int digits = 0; do { number /= 10; digits++; } while (number != 0);

(Gracias Kevin Fegan)

Al final, use un generador de perfiles para saber cuál de todas las respuestas aquí será más rápida en su máquina ...


3
Esto puede o no ser más rápido que el enfoque de bucle desenrollado que tomé: necesitaría perfilar la diferencia (a largo plazo debería ser insignificante).
Vitali

De acuerdo, la creación de perfiles es la única forma de saberlo con certeza. Actualicé mi respuesta con ese comentario, ya que la respuesta ceil (log10 ()) de Ben S ha desaparecido.
squelart

11

Broma práctica: esta es la forma más eficiente (el número de dígitos se calcula en tiempo de compilación):

template <unsigned long long N, size_t base=10>
struct numberlength
{
    enum { value = 1 + numberlength<N/base, base>::value };
};

template <size_t base>
struct numberlength<0, base>
{
    enum { value = 0 };
};

Puede ser útil para determinar el ancho requerido para el campo numérico en formato, elementos de entrada, etc.


44
Primero, su solución no funciona para 0. Segundo, su solución no es aplicable al caso general de una variable. En tercer lugar, si está utilizando un literal constante, ya sabe cuántos dígitos tiene.
Vitali

Funciona para 0 también. También funciona para cualquier base. El resto son puntos válidos que ya describí.
blinnov.com

3
No creo que lo haga en realidad. Falla en 0y también falla en base 1:) y da divide por cero errores si la base se da como 0. Sin embargo, se puede arreglar. De todos modos, estoy revisando una publicación muy antigua, lo siento, es solo que creo que esto no tiene por qué ser una broma y podría ser útil.
tjm

9

Vea Bit Twiddling Hacks para una versión mucho más corta de la respuesta que aceptó. También tiene la ventaja de encontrar la respuesta antes si su entrada se distribuye normalmente, verificando primero las constantes grandes. (v >= 1000000000)captura el 76% de los valores, por lo que comprobar que primero será, en promedio, más rápido.


No está claro si el bit-twiddling es realmente más rápido. Incluso en el peor de los casos, mi enfoque modificado requiere 4 comparaciones (podría ser capaz de reducirlo a 3 si examiné la partición más a fondo, aunque parece poco probable). Dudo seriamente que eso vaya a ser superado por las operaciones aritméticas + las cargas de memoria (aunque si se accede lo suficiente, desaparecerán en el caché de la CPU). Recuerde, en el ejemplo que dan, también ocultan la base de registro 2 como alguna función abstracta de IntegerLogBase2 (que en sí misma no es barata).
Vitali

Solo como seguimiento, sí, si los números se distribuyen normalmente, hacer la verificación en orden es más rápido. Sin embargo, tiene el caso degenerado de ser el doble de lento en el peor de los casos. El enfoque dividido por número de dígitos en lugar de espacio de entrada significa que el comportamiento no tiene un caso degenerado y siempre funciona de manera óptima. Además, recuerde que está asumiendo que los números se distribuirán uniformemente. De hecho, son más propensos a seguir alguna distribución relacionada con <a href=" en.wikipedia.org/wiki/...> sería mi conjetura.
Vitali

Los trucos de twiddling no son más rápidos que el método de partición anterior, pero son potencialmente interesantes si tuviera un caso más general como un flotante aquí.
Corwin Joy

1
Los trucos de twiddling sugieren una forma de obtener int log10, dado int log2. Sugiere varias formas de obtener int log2, principalmente con pocas comparaciones / ramas. (Creo que estás subestimando el costo de las ramas impredecibles, Vitali). Si puede utilizar inmx x86 asm, la instrucción BSR le dará el log2 int de un valor (es decir, el índice de bits del bit de conjunto más significativo). Es un poco lento en K8 (latencia de 10 ciclos), pero rápido en Core 2 (latencia de 2 o 3 ciclos). Incluso en K8, puede ser más rápido que las comparaciones.
Peter Cordes

En K10, lzcnt cuenta los ceros iniciales, por lo que es casi lo mismo que bsr, pero una entrada de 0 ya no es un caso especial con resultados indefinidos. Latencias: BSR: 4, LZCNT: 2.
Peter Cordes

8

convertir a cadena y luego usar funciones integradas

unsigned int i;
cout<< to_string(i).length()<<endl;

7
int x = 1000;
int numberOfDigits = x ? static_cast<int>(log10(abs(x))) + 1 : 1;

3
Si bien esto es eficiente en términos de LOC, como se señaló en la respuesta aceptada, el uso del registro probablemente no dará el mejor rendimiento.
Ian

@ Ian ¿Por qué no? Son solo un par de instrucciones de FPU. Millas mejor que todas las ramas y bucles en otras respuestas.
Marqués de Lorne

5

Un póster anterior sugirió un bucle que se divide entre 10. Dado que las multiplicaciones en máquinas modernas son mucho más rápidas, recomendaría el siguiente código:

 int digits = 1, pten=10; while ( pten <= number ) { digits++; pten*=10; }

1
el diablo está en los detalles - lo que sucede con say std :: numeric_limits <int> :: max == number - podría tener un problema para terminar
pgast

2
Si le preocupa ese caso, puede agregar un IF adicional para manejar valores muy grandes.
Ira Baxter

2
Debo observar que en las máquinas x86, el compilador puede implementar una multiplicación por una constante 10, como se usa en este caso, como LEA R2, [8 * R1 + R1], AGREGAR R1, R2, por lo que se necesitan 2 relojes como máximo. Las multiplicaciones por variables toman decenas de relojes, y las divisiones son mucho peores.
Ira Baxter

La ventaja del enfoque de división es que no necesita preocuparse por los números negativos.
Johannes Schaub - litb

1
Comparé el enfoque de multiplicación (con fabs para eliminar el problema de los signos) versus el enfoque de división. En mi máquina, el enfoque de división es un factor 2 más lento que el enfoque de multiplicación. Si esto es una optimización prematura o no, realmente depende de dónde y cómo se llama.
Spacemoose

5

La arquitectura ppc tiene un poco de instrucción de conteo. Con eso, puede determinar la base de registro 2 de un entero positivo en una sola instrucción. Por ejemplo, 32 bits sería:

#define log_2_32_ppc(x) (31-__cntlzw(x))

Si puede manejar un pequeño margen de error en valores grandes, puede convertirlo a la base 10 de registro con otras pocas instrucciones:

#define log_10_estimate_32_ppc(x) (9-(((__cntlzw(x)*1233)+1545)>>12))

Esto es específico de la plataforma y es un poco impreciso, pero tampoco implica ramas, división o conversión a coma flotante. Todo depende de lo que necesites.

Solo conozco las instrucciones de ppc, pero otras arquitecturas deberían tener instrucciones similares.


Esta solución calcula log2 (15) = 4 bits y log2 (9) = 4 bits. Pero 15 y 9 requieren diferentes números de dígitos decimales para imprimir. Por lo tanto, no funciona, a menos que a veces no le importe imprimir sus números con demasiados dígitos. Pero en ese caso, siempre puede elegir "10" como respuesta para int.
Ira Baxter

Wow, una función aproximada. Agradable.
doug65536

4
 #include <iostream>
 #include <math.h>

 using namespace std;

 int main()
 {
     double num;
     int result;
     cout<<"Enter a number to find the number of digits,  not including decimal places: ";
     cin>>num;
     result = ((num<=1)? 1 : log10(num)+1);
     cout<<"Number of digits "<<result<<endl;
     return 0;
 }

Esta es probablemente la forma más sencilla de resolver su problema, suponiendo que solo le importen los dígitos antes del decimal y suponiendo que cualquier cosa menor que 10 es solo 1 dígito.


1

Me gusta la respuesta de Ira Baxter. Aquí hay una variante de plantilla que maneja los diversos tamaños y se ocupa de los valores enteros máximos (actualizados para izar el check-out del límite superior del bucle):

#include <boost/integer_traits.hpp>

template<typename T> T max_decimal()
{
    T t = 1;

    for (unsigned i = boost::integer_traits<T>::digits10; i; --i)
        t *= 10;

    return t;
}

template<typename T>
unsigned digits(T v)
{
    if (v < 0) v = -v;

    if (max_decimal<T>() <= v)
        return boost::integer_traits<T>::digits10 + 1;

    unsigned digits = 1;
    T boundary = 10;

    while (boundary <= v) {
        boundary *= 10;
        ++digits;
    }

    return digits;
}

Para obtener realmente el rendimiento mejorado al levantar la prueba adicional del ciclo, debe especializarse max_decimal () para devolver constantes para cada tipo en su plataforma. Un compilador suficientemente mágico podría optimizar la llamada a max_decimal () a una constante, pero la especialización es mejor con la mayoría de los compiladores de hoy. Tal como está, esta versión es probablemente más lenta porque max_decimal cuesta más que las pruebas eliminadas del bucle.

Dejaré todo eso como ejercicio para el lector.


Desea hacer que el límite superior verifique un condicional separado probado primero para que no lo verifique en cada iteración del bucle.
Ira Baxter

No quieres poner 10 en esa temperatura. El compilador podría considerar multiplicar por t para multiplicar por una variable real, y utilizar una instrucción de multiplicación de propósito general. Si en su lugar escribió "resultado * = 10;" el compilador seguramente notará la multiplicación por 10 constantes e implementará eso con unos pocos cambios y adiciones, lo cual es extremadamente rápido.
Ira Baxter

Si la multiplicación por t siempre fue una multiplicación por 10, entonces sí, el compilador podría reducir la fuerza. Sin embargo, t no es invariante en bucle en este caso (es solo una modificación de una función de potencia entera que tenía por ahí). La optimización correcta es la especialización en el tipo que devuelve una constante. Sin embargo, tiene razón en que, en este caso, la función siempre está elevando 10 a una potencia, no un entero arbitrario a una potencia, y la reducción de la fuerza da una buena victoria. Así que hice un cambio ... ¡Esta vez más cambios realmente quedan como ejercicio! (Stack Overflow es un gran sumidero ...)
enero

1
#include <stdint.h> // uint32_t [available since C99]

/// Determine the number of digits for a 32 bit integer.
/// - Uses at most 4 comparisons.
/// - (cX) 2014 adolfo.dimare@gmail.com
/// - \see http://stackoverflow.com/questions/1489830/#27669966
/**  #d == Number length vs Number of comparisons == #c
     \code
         #d | #c   #d | #c
         ---+---   ---+---
         10 | 4     5 | 4
          9 | 4     4 | 4
          8 | 3     3 | 3
          7 | 3     2 | 3
          6 | 3     1 | 3
     \endcode
*/
unsigned NumDigits32bs(uint32_t x) {
    return // Num-># Digits->[0-9] 32->bits bs->Binary Search
    ( x >= 100000u // [6-10] [1-5]
    ?   // [6-10]
        ( x >= 10000000u // [8-10] [6-7]
        ?   // [8-10]
            ( x >= 100000000u // [9-10] [8]
            ? // [9-10]
                ( x >=  1000000000u // [10] [9]
                ?   10
                :    9
                )
            : 8
            )
        :   // [6-7]
            ( x >=  1000000u // [7] [6]
            ?   7
            :   6
            )
        )
    :   // [1-5]
        ( x >= 100u // [3-5] [1-2]
        ?   // [3-5]
            ( x >= 1000u // [4-5] [3]
            ? // [4-5]
                ( x >=  10000u // [5] [4]
                ?   5
                :   4
                )
            : 3
            )
        :   // [1-2]
            ( x >=  10u // [2] [1]
            ?   2
            :   1
            )
        )
    );
}

0

Otro fragmento de código, que hace básicamente lo mismo que Vitali, pero emplea la búsqueda binaria. La matriz Powers se inicializa de forma diferida una vez por cada instancia de tipo sin signo. La sobrecarga de tipo firmado se encarga del signo menos.

#include <limits>
#include <type_traits>
#include <array>

template <class T> 
size_t NumberOfDecPositions ( T v, typename std::enable_if<std::is_unsigned<T>::value>::type* = 0 )
{
    typedef std::array<T,std::numeric_limits<T>::digits10+1> array_type;
    static array_type powers_of_10;
    if ( powers_of_10.front() == 0 )
    {
        T n = 1;
        for ( T& i: powers_of_10 )
        {
            i = n;
            n *= 10;
        }
    }

    size_t l = 0, r = powers_of_10.size(), p;
    while ( l+1 < r )
    {
        p = (l+r)/2;
        if ( powers_of_10[p] <= v )
            l = p;
        else
            r = p;
    }
    return l + 1;
};

template <class T> 
size_t NumberOfDecPositions ( T v, typename std::enable_if<std::is_signed<T>::value>::type* = 0 )
{
    typedef typename std::make_unsigned<T>::type unsigned_type;
    if ( v < 0 )
        return NumberOfDecPositions ( static_cast<unsigned_type>(-v) ) + 1;
    else
        return NumberOfDecPositions ( static_cast<unsigned_type>(v) );
}

Si a alguien le importa una mayor optimización, tenga en cuenta que el primer elemento de la matriz de poderes nunca se usa, y laparece con +12 veces.


0

en caso de que se necesite el número de dígitos Y el valor de cada posición de dígitos, use esto:

int64_t = number, digitValue, digits = 0;    // or "int" for 32bit

while (number != 0) {
    digitValue = number % 10;
    digits ++;
    number /= 10;
}

digitle da el valor en la posición del número que se procesa actualmente en el bucle. por ejemplo, para el número 1776, el valor del dígito es:
6 en el 1er bucle
7 en el 2 ° bucle
7 en el 3 ° bucle
1 en el 4 ° bucle


0
// Meta-program to calculate number of digits in (unsigned) 'N'.    
template <unsigned long long N, unsigned base=10>
struct numberlength
{   // http://stackoverflow.com/questions/1489830/
    enum { value = ( 1<=N && N<base ? 1 : 1+numberlength<N/base, base>::value ) };
};

template <unsigned base>
struct numberlength<0, base>
{
    enum { value = 1 };
};

{
    assert( (1 == numberlength<0,10>::value) );
}
assert( (1 == numberlength<1,10>::value) );
assert( (1 == numberlength<5,10>::value) );
assert( (1 == numberlength<9,10>::value) );

assert( (4 == numberlength<1000,10>::value) );
assert( (4 == numberlength<5000,10>::value) );
assert( (4 == numberlength<9999,10>::value) );

Corrección para "Broma práctica" de 'blinnov.com' arriba
Adolfo

0
/// Determine the number of digits for a 64 bit integer.
/// - Uses at most 5 comparisons.
/// - (cX) 2014 adolfo.dimare@gmail.com
/// - \see http://stackoverflow.com/questions/1489830/#27670035
/**  #d == Number length vs Number of comparisons == #c
     \code
         #d | #c   #d | #c     #d | #c   #d | #c
         ---+---   ---+---     ---+---   ---+---
         20 | 5    15 | 5      10 | 5     5 | 5
         19 | 5    14 | 5       9 | 5     4 | 5
         18 | 4    13 | 4       8 | 4     3 | 4
         17 | 4    12 | 4       7 | 4     2 | 4
         16 | 4    11 | 4       6 | 4     1 | 4
     \endcode
*/
unsigned NumDigits64bs(uint64_t x) {
    return // Num-># Digits->[0-9] 64->bits bs->Binary Search
    ( x >= 10000000000ul // [11-20] [1-10]
    ?
        ( x >= 1000000000000000ul // [16-20] [11-15]
        ?   // [16-20]
            ( x >= 100000000000000000ul // [18-20] [16-17]
            ?   // [18-20]
                ( x >= 1000000000000000000ul // [19-20] [18]
                ? // [19-20]
                    ( x >=  10000000000000000000ul // [20] [19]
                    ?   20
                    :   19
                    )
                : 18
                )
            :   // [16-17]
                ( x >=  10000000000000000ul // [17] [16]
                ?   17
                :   16
                )
            )
        :   // [11-15]
            ( x >= 1000000000000ul // [13-15] [11-12]
            ?   // [13-15]
                ( x >= 10000000000000ul // [14-15] [13]
                ? // [14-15]
                    ( x >=  100000000000000ul // [15] [14]
                    ?   15
                    :   14
                    )
                : 13
                )
            :   // [11-12]
                ( x >=  100000000000ul // [12] [11]
                ?   12
                :   11
                )
            )
        )
    :   // [1-10]
        ( x >= 100000ul // [6-10] [1-5]
        ?   // [6-10]
            ( x >= 10000000ul // [8-10] [6-7]
            ?   // [8-10]
                ( x >= 100000000ul // [9-10] [8]
                ? // [9-10]
                    ( x >=  1000000000ul // [10] [9]
                    ?   10
                    :    9
                    )
                : 8
                )
            :   // [6-7]
                ( x >=  1000000ul // [7] [6]
                ?   7
                :   6
                )
            )
        :   // [1-5]
            ( x >= 100ul // [3-5] [1-2]
            ?   // [3-5]
                ( x >= 1000ul // [4-5] [3]
                ? // [4-5]
                    ( x >=  10000ul // [5] [4]
                    ?   5
                    :   4
                    )
                : 3
                )
            :   // [1-2]
                ( x >=  10ul // [2] [1]
                ?   2
                :   1
                )
            )
        )
    );
}

0

para el número entero 'X' desea saber la cantidad de dígitos, bien sin usar ningún bucle, esta solución actúa en una fórmula en una sola línea, por lo que esta es la solución más óptima que he visto para este problema.

 int x = 1000 ; 
 cout<<numberOfDigits = 1+floor(log10(x))<<endl ; 

Falla para INT_MAX y también para números negativos.
Ranu

@ranu falla para INT_MAX ¿cómo? Cuando el argumento se convierte a double? ¿O se refiere a alguna entrada entera imposible con dígitos decimales INT_MAX? ¿Cuál también fallaría en cualquier otra respuesta aquí?
Marqués de Lorne

0
int numberOfDigits(int n){

    if(n<=9){
        return 1;
    }
    return 1 + numberOfDigits(n/10);
}

Esto es lo que haría, si lo desea para la base 10. Es bastante rápido y no obtendrá un overflock de apilamiento de enteros enteros.


0
int num,dig_quant = 0;
cout<<"\n\n\t\t--Count the digits in Number--\n\n";
cout<<"Enter Number: ";
cin>>num;
for(int i = 1; i<=num; i*=10){
    if(num / i  > 0){
      dig_quant += 1;
    }
}
 cout<<"\n"<<number<<" include "<<dig_quant<<" digit"
 cout<<"\n\nGoodbye...\n\n";

0

Si más rápido es más eficiente, esta es una mejora en la mejora de andrei alexandrescu . Su versión ya era más rápida que la forma ingenua (dividiendo por 10 en cada dígito). La versión a continuación es de tiempo constante y más rápido al menos en x86-64 y ARM para todos los tamaños, pero ocupa el doble de código binario, por lo que no es tan amigable para la caché.

Los puntos de referencia para esta versión vs la versión de alexandrescu en mi PR en Facebook locura .

Funciona en unsigned, no signed.

inline uint32_t digits10(uint64_t v) {
  return  1
        + (std::uint32_t)(v>=10)
        + (std::uint32_t)(v>=100)
        + (std::uint32_t)(v>=1000)
        + (std::uint32_t)(v>=10000)
        + (std::uint32_t)(v>=100000)
        + (std::uint32_t)(v>=1000000)
        + (std::uint32_t)(v>=10000000)
        + (std::uint32_t)(v>=100000000)
        + (std::uint32_t)(v>=1000000000)
        + (std::uint32_t)(v>=10000000000ull)
        + (std::uint32_t)(v>=100000000000ull)
        + (std::uint32_t)(v>=1000000000000ull)
        + (std::uint32_t)(v>=10000000000000ull)
        + (std::uint32_t)(v>=100000000000000ull)
        + (std::uint32_t)(v>=1000000000000000ull)
        + (std::uint32_t)(v>=10000000000000000ull)
        + (std::uint32_t)(v>=100000000000000000ull)
        + (std::uint32_t)(v>=1000000000000000000ull)
        + (std::uint32_t)(v>=10000000000000000000ull);
}

0

Estaba trabajando en un programa que requería que verificara si el usuario respondía correctamente cuántos dígitos había en un número, por lo que tuve que desarrollar una forma de verificar la cantidad de dígitos en un número entero. Terminó siendo algo relativamente fácil de resolver.

double check=0, exponent=1000;

while(check<=1)
{
    check=number/pow(10, exponent);
    exponent--;
}

exponent=exponent+2;
cout<<exponent<<endl;

Esta terminó siendo mi respuesta, que actualmente funciona con números con menos de 10 ^ 1000 dígitos (se puede cambiar cambiando el valor del exponente).

PD: Sé que esta respuesta tiene diez años de retraso, pero llegué aquí en 2020 para que otras personas puedan usarla.


-1
template <typename type>
class number_of_decimal_digits {   
    const powers_and_max<type> mPowersAndMax;
public:
    number_of_decimal_digits(){
    }   
    inline size_t ndigits( type i) const {
        if(i<0){
             i += (i == std::numeric_limits<type>::min());
             i=-i;
        }
        const type* begin = &*mPowersAndMax.begin();
        const type* end = begin+mPowersAndMax.size();
        return 1 + std::lower_bound(begin,end,i) - begin;
    }
    inline size_t string_ndigits(const type& i) const {
        return (i<0) + ndigits(i);
    }
    inline size_t operator[](const type& i) const {
       return string_ndigits(i);
    }
};

donde powers_and_maxtenemos (10^n)-1para todos los nque

(10^n) < std::numeric_limits<type>::max()

y std::numeric_limits<type>::max()en una matriz:

template <typename type>
struct powers_and_max : protected std::vector<type>{
    typedef std::vector<type> super;
    using super::const_iterator;
    using super::size;
    type& operator[](size_t i)const{return super::operator[](i)};
    const_iterator begin()const {return super::begin();} 
    const_iterator end()const {return super::end();} 
    powers_and_max() {
       const int size = (int)(log10(double(std::numeric_limits<type>::max())));
       int j = 0;
       type i = 10;
       for( ; j<size ;++j){
           push_back(i-1);//9,99,999,9999 etc;
           i*=10;
       }
       ASSERT(back()<std::numeric_limits<type>::max());
       push_back(std::numeric_limits<type>::max());
   }
};

Aquí hay una prueba simple:

number_of_decimal_digits<int>  ndd;
ASSERT(ndd[0]==1);
ASSERT(ndd[9]==1);
ASSERT(ndd[10]==2);
ASSERT(ndd[-10]==3);
ASSERT(ndd[-1]==2);
ASSERT(ndd[-9]==2);
ASSERT(ndd[1000000000]==10);
ASSERT(ndd[0x7fffffff]==10);
ASSERT(ndd[-1000000000]==11);
ASSERT(ndd[0x80000000]==11);

Por supuesto, podría usarse cualquier otra implementación de un conjunto ordenado powers_and_maxy, si se supiera que habría agrupamiento, pero no se sabe dónde podría estar el clúster, tal vez sería mejor una implementación de árbol autoajustable


-1

manera efectiva

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

#include <iostream>

int main()
{
   int num;
   std::cin >> num;

   std::cout << "number of digits for " << num << ": ";

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

   std::cout << count << '\n';

   return 0;
}

-1

Actualización de C ++ 11 de la solución preferida:

#include <limits>
#include <type_traits>
        template <typename T>
        typename std::enable_if<std::numeric_limits<T>::is_integer, unsigned int>::type
        numberDigits(T value) {
            unsigned int digits = 0;
            if (value < 0) digits = 1;
            while (value) {
                value /= 10;
                ++digits;
            }
            return digits;
        }

evita la creación de instancias de plantilla con doble, et. Alabama.


-1
int numberOfDigits(double number){
    if(number < 0){
        number*=-1;
    }
    int i=0;
        while(number > pow(10, i))
            i++;    
    cout << "This number has " << i << " digits" << endl;
    return i;
}

-2

Esta es mi forma de hacer eso:

   int digitcount(int n)
    {
        int count = 1;
        int temp = n;
        while (true)
        {
            temp /= 10;
            if (temp != 0) ++count;
            if (temp == 0) break;
        }

        return count;
    }

2
mientras verdadero / síndrome de ruptura: D
Петър Петров

-1 este es el mismo enfoque que dio la primera respuesta seis años antes, y no agrega nada (de hecho, es significativamente peor).

-4

Aquí hay un enfoque diferente:

digits = sprintf(numArr, "%d", num);    // where numArr is a char array
if (num < 0)
    digits--;

Esto puede no ser eficiente, solo algo diferente de lo que otros sugirieron.


44
La solicitud fue extremadamente eficiente. Esto es lo contrario.
Ira Baxter
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.