Modo efficiente per determinare il numero di cifre in un numero intero


145

Qual è un modo molto efficace per determinare quante cifre ci sono in un numero intero in C ++?


11
In quale base? 2? 10?
Jacob Krall,

2
Vorrei farlo nella base 10
Seth,

1
Una volta ho posto una domanda correlata: come puoi ottenere la prima cifra in un int? Molte delle stesse metodologie di seguito sono state utilizzate nelle risposte delle persone. Ecco il link nel caso in cui sia rilevante per il tuo compito [ stackoverflow.com/questions/701322/]
Dinah,

L'assemblaggio in linea si qualifica?
György Andrasek,

1
Mentre tutte queste risposte sono in termini di base 10, è abbastanza facile cambiare per calcolare il risultato per qualsiasi base desiderata.
Ira Baxter,

Risposte:


106

Bene, il modo più efficiente, presumendo che tu conosca la dimensione dell'intero, sarebbe una ricerca. Dovrebbe essere più veloce dell'approccio basato sul logaritmo molto più breve. Se non ti interessa contare "-", rimuovi + 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];
}

5
Probabilmente più veloce della mia risposta, ben fatto. Per maggiore efficienza, se sai che i tuoi numeri di input saranno per lo più piccoli (suppongo che siano meno di 100.000), quindi inverti i test: if (x <10) restituisce 1; se (x <100) restituisce 2; ecc., in modo che la funzione esegua meno test e termini più rapidamente.
Squelart,

29
O forse riordinare e annidare le istruzioni if, per eseguire una ricerca binaria anziché una ricerca lineare.
dave4420,

1
Non è una buona idea. Cosa succede quando l'architettura si espande a numeri interi a 256 bit. Devi ricordare di tornare e modificare questo codice. Nella vita reale ciò non accadrà e sicuramente questo sarà probabilmente usato per costruire un buffer della dimensione corretta che ora ti stai aprendo a tutti i tipi di problemi di buffer over run su architetti più grandi.
Martin York,

3
supponendo una distribuzione uniforme dei numeri, la ricerca lineare inversa (a partire da cifre massime a 1) può essere mediamente più veloce della ricerca binaria in quanto vi sono molti più numeri con N cifre rispetto a N-1 cifre graphics.stanford.edu/~ seander / ...
fa.

6
Non mi preoccuperei molto per i numeri interi a 256 o 128 bit. A meno che non sia necessario contare il numero di elettroni nell'Universo (10 ^ 78 l'ultima volta che l'ho fatto), 64 bit funzioneranno abbastanza bene. Le macchine a 32 bit sono durate ~ ~ 15 anni. Immagino che le macchine a 64 bit dureranno molto più a lungo. Per un numero maggiore, l'aritmetica multiprecisione andrà bene e dubito che l'efficacia del conteggio delle cifre di calcolo sia importante.
Ira Baxter,

74

Il modo più semplice è fare:

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

log10 è definito in <cmath>o <math.h>. Dovresti profilare questo per vedere se è più veloce di tutti gli altri pubblicati qui. Non sono sicuro di quanto sia robusto per quanto riguarda la precisione in virgola mobile. Inoltre, l'argomento non è firmato come valori negativi e il registro non si mescola realmente.


7
Per 32 bit e float a 56 bit, probabilmente funziona. Se l'input è lungo (64 bit), i 56 bit del registro a doppia precisione potrebbero causare una risposta errata in caso di valori vicini a valori elevati di 10 ^ n. Aspettatevi guai superiori a 2 ^ 50.
Ira Baxter,

1
C'è anche la questione della precisione delle funzioni di registro. Non ho verificato quanto siano accurati nelle biblioteche moderne e non mi sentirei a mio agio nel fidarmi ciecamente di essere buoni in una parte su un miliardo.
David Thornley,

@DavidThornley: il registro o altre funzioni matematiche sono perfettamente precisi se non specificato nella riga di comando del compilatore. alcuni saranno convertiti in intrinseci x86 al momento della compilazione. alcuni non esistono e si espanderanno in formule di intrinseci esistenti. ad esempio, se si utilizza -fpfastè possibile vedere l'uso di strumenti SSE anziché x87, che offre meno garanzie sull'IRLC di precisione. ma per impostazione predefinita nessun problema.
v.

@DavidThornley: è più che precisione. La domanda è se è garantito o meno quel log10 (10 ^ k) ≥ k per tutti i k rilevanti. Cioè è garantito che qualsiasi inevitabile errore di arrotondamento vada nella giusta direzione. k + eps di conseguenza funziona, k - eps no. E "Perfettamente preciso" è ingenuo.
gnasher729

1
Il test i> 0 potrebbe essere ottimizzato per i> 9
Pat

60

Forse ho frainteso la domanda ma non lo fa?

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
E non sarei sorpreso se questa soluzione fosse la più veloce.
VisioN,

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

Nota: "0" avrà 0 cifre! Se hai bisogno di 0 per sembrare avere 1 cifra, usa:

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

(Grazie Kevin Fegan)

Alla fine, usa un profiler per sapere quale delle risposte qui sarà più veloce sulla tua macchina ...


3
Questo potrebbe essere o non essere più veloce dell'approccio del ciclo srotolato che ho adottato - dovresti profilare la differenza (dovrebbe essere trascurabile nel lungo periodo).
Vitali,

D'accordo, la profilazione è l'unico modo per saperlo con certezza! Ho aggiornato la mia risposta con quel commento, poiché la risposta ceil (log10 ()) di Ben S è scomparsa.
Squelart,

11

Scherzo pratico: questo è il modo più efficiente (il numero di cifre viene calcolato in fase di compilazione):

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 };
};

Può essere utile per determinare la larghezza richiesta per il campo numerico in formattazione, elementi di input ecc.


4
Innanzitutto, la soluzione non funziona per 0. In secondo luogo, la soluzione non è applicabile al caso generale di una variabile. In terzo luogo, se stai usando un valore letterale costante, sai già quante cifre ha.
Vitali,

Funziona anche per 0. Funziona anche con qualsiasi base. Il resto sono punti validi che ho già delineato.
blinnov.com,

3
In realtà non penso. Non riesce 0e fallisce anche sulla base 1:) e dà la divisione per zero errori se la base viene data come 0. Tuttavia, può essere risolto. Ad ogni modo sto puntando su un post molto vecchio, quindi mi dispiace, è solo che penso che questo non debba essere uno scherzo e potrebbe effettivamente essere utile.
tjm

9

Vedi Bit Twiddling Hacks per una versione molto più breve della risposta che hai accettato. Ha anche il vantaggio di trovare la risposta prima se l'input è normalmente distribuito, controllando prima le costanti grandi. (v >= 1000000000)rileva il 76% dei valori, quindi verificare che in primo luogo sia in media più veloce.


Non è chiaro se il bit-twiddling sia effettivamente più veloce. Anche nel peggiore dei casi, il mio approccio modificato richiede 4 confronti (potrebbe essere in grado di portarlo a 3 se avessi esaminato ulteriormente il partizionamento, anche se sembra improbabile). Dubito seriamente che questo sarà battuto da operazioni aritmetiche + carichi di memoria (anche se se accessibili abbastanza, quelli scompaiono nella cache della CPU). Ricorda, nell'esempio che danno, nascondono anche la base di registro 2 come una funzione astratta IntegerLogBase2 (che di per sé non è economica).
Vitali,

Proprio come follow-up, sì se i numeri sono normalmente distribuiti, fare il controllo in ordine è più veloce. Tuttavia, ha il caso degenerato di essere due volte più lento nel caso peggiore. L'approccio partizionato per numero di cifre anziché per spazio di input significa che il comportamento non ha un caso degenerato e funziona sempre in modo ottimale. Inoltre, ricorda che stai assumendo che i numeri saranno distribuiti uniformemente. In effetti, è più probabile che seguano alcune distribuzioni relative a <a href=" en.wikipedia.org/wiki/…> sarebbe la mia ipotesi.
Vitali,

Gli hack bit twiddling non sono più veloci del metodo di partizione sopra, ma sono potenzialmente interessanti se qui avessi un caso più generale come un float.
Corwin Joy,

1
Gli hack bit twiddling suggeriscono un modo per ottenere int log10, dato int log2. Suggerisce diversi modi per ottenere int log2, che coinvolge principalmente pochi confronti / rami. (Penso che tu stia sottovalutando il costo di rami imprevedibili, Vitali). Se è possibile utilizzare x86 asm inline, l'istruzione BSR fornisce l'int2 log2 di un valore (ovvero l'indice di bit di un bit impostato più significativo). È un po 'lento su K8 (latenza di 10 cicli), ma veloce su Core 2 (latenza di 2 o 3 cicli). Anche su K8, potrebbe essere più veloce dei confronti.
Peter Cordes,

Su K10, lzcnt conta gli zeri iniziali, quindi è quasi lo stesso di bsr, ma un input di 0 non è più un caso speciale con risultati indefiniti. Latenze: BSR: 4, LZCNT: 2.
Peter Cordes,

8

convertire in stringa e quindi utilizzare le funzioni integrate

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
Sebbene ciò sia efficiente in termini di LOC, come indicato nella risposta accettata, l'uso del registro probabilmente non fornirà le migliori prestazioni.
Ian

@Ian Perché no? Sono solo un paio di istruzioni FPU. Miglia meglio di tutti i rami e gli anelli nelle altre risposte.
Marchese di Lorne il

5

Un poster precedente suggeriva un ciclo che si divide per 10. Poiché le moltiplicazioni su macchine moderne sono molto più veloci, raccomanderei invece il seguente codice:

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

1
il diavolo è nei dettagli - cosa succede con dire std :: numeric_limits <int> :: max == numero - potrebbe avere un problema a terminare
pgast

2
Se sei preoccupato per quel caso, puoi aggiungere un ulteriore IF per gestire valori molto grandi.
Ira Baxter,

2
Dovrei osservare che su macchine x86, un moltiplicatore per una costante 10 usato in questo caso può effettivamente essere implementato dal compilatore come LEA R2, [8 * R1 + R1], ADD R1, R2, quindi ci vogliono 2 clock al massimo. La moltiplicazione per variabili richiede decine di orologi e le divisioni sono molto peggio.
Ira Baxter,

il vantaggio con l'approccio di divisione è che non devi preoccuparti di numeri negativi.
Johannes Schaub - litb

1
Ho confrontato l'approccio della moltiplicazione (con un fab per rimuovere il problema del segno) rispetto all'approccio della divisione. Sulla mia macchina l'approccio alla divisione è il fattore 2 più lento dell'approccio alla moltiplicazione. Che si tratti di ottimizzazione prematura o meno dipende da dove e come viene chiamato.
Spacemoose

5

L'architettura ppc ha delle istruzioni per il conteggio dei bit. Con ciò, è possibile determinare la base di log 2 di un numero intero positivo in una singola istruzione. Ad esempio, 32 bit sarebbe:

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

Se riesci a gestire un piccolo margine di errore su valori di grandi dimensioni, puoi convertirlo in log base 10 con altre poche istruzioni:

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

Questo è specifico per la piattaforma e leggermente impreciso, ma non comporta anche rami, divisione o conversione in virgola mobile. Tutto dipende da cosa ti serve.

Conosco solo le istruzioni ppc, ma altre architetture dovrebbero avere istruzioni simili.


Questa soluzione calcola log2 (15) = 4 bit e log2 (9) = 4 bit. Ma 15 e 9 richiedono numeri diversi di cifre decimali per la stampa. Quindi non funziona, a meno che a volte non ti dispiaccia stampare i tuoi numeri con troppe cifre. Ma in tal caso, puoi sempre scegliere "10" come risposta per int.
Ira Baxter,

Wow, una funzione approssimativa. Bello.
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;
 }

Questo è probabilmente il modo più semplice per risolvere il tuo problema, supponendo che ti interessi solo delle cifre prima del decimale e supponendo che qualcosa di meno di 10 sia solo 1 cifra.


1

Mi piace la risposta di Ira Baxter. Ecco una variante di modello che gestisce le varie dimensioni e gestisce i valori interi massimi (aggiornati per sollevare il check out del limite superiore dal loop):

#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;
}

Per ottenere effettivamente le prestazioni migliorate sollevando il test aggiuntivo fuori dal ciclo, è necessario specializzare max_decimal () per restituire costanti per ogni tipo sulla piattaforma. Un compilatore sufficientemente magico potrebbe ottimizzare la chiamata a max_decimal () su una costante, ma oggi la specializzazione è migliore con la maggior parte dei compilatori. Allo stato attuale, questa versione è probabilmente più lenta perché max_decimal costa più dei test rimossi dal loop.

Lascio tutto questo come esercizio per il lettore.


Vuoi fare in modo che il limite superiore verifichi prima un test condizionale separato in modo da non verificarlo su ogni iterazione di loop.
Ira Baxter,

Non vuoi mettere 10 in quella temperatura. Il compilatore potrebbe considerare di moltiplicare per t moltiplicare per una variabile reale e utilizzare un'istruzione di moltiplicazione per scopi generici. Se invece hai scritto "risultato * = 10;" il compilatore noterà sicuramente il moltiplicarsi per la costante 10 e lo implementerà con pochi turni e aggiunte, il che è estremamente veloce.
Ira Baxter,

Se la moltiplicazione per t è stata sempre una moltiplicazione per 10, allora sì, il compilatore potrebbe ridurre la forza. Tuttavia, in questo caso t non è invarianza di loop (è solo una modifica di una funzione di potenza intera che avevo in giro). L'ottimizzazione corretta è la specializzazione sul tipo che restituisce una costante. Tuttavia, hai ragione nel dire che, in questo caso, la funzione aumenta sempre 10 a una potenza, non un numero intero arbitrario a una potenza, e la riduzione della forza dà una buona vittoria. Quindi ho fatto un cambiamento ... Questa volta ulteriori cambiamenti sono davvero lasciati come esercizio! (Stack Overflow è un grosso
problema

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

Ancora un altro frammento di codice, che fa sostanzialmente lo stesso di Vitali ma impiega la ricerca binaria. L'array Powers viene inizializzato lentamente una volta per ogni istanza di tipo senza segno. Il sovraccarico del tipo firmato si occupa del segno meno.

#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) );
}

Se qualcuno si preoccupa di un'ulteriore ottimizzazione, tieni presente che il primo elemento dell'array power non viene mai utilizzato e lappare +12 volte.


0

nel caso in cui sia necessario il numero di cifre E il valore di ciascuna posizione, utilizzare questo:

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

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

digitti dà il valore nella posizione numerica che è attualmente elaborata nel ciclo. ad esempio per il numero 1776 il valore della cifra è:
6 nel 1 ° ciclo
7 nel 2 ° ciclo
7 nel 3 ° ciclo
1 nel 4 ° ciclo


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) );

Correzione per "Scherzo pratico" da 'blinnov.com' sopra
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

per intero 'X' vuoi conoscere il numero di cifre, va bene senza usare alcun loop, questa soluzione agisce in una formula in una riga solo quindi questa è la soluzione più ottimale che abbia mai visto a questo problema.

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

Non riesce per INT_MAX e anche per i numeri negativi.
ranu,

@ranu non è riuscito a INT_MAX come? Quando l'argomento viene convertito in double? O ti riferisci a qualche input intero impossibile con cifre decimali INT_MAX? Che fallirebbe anche ogni altra risposta qui?
Marchese di Lorne il

0
int numberOfDigits(int n){

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

Questo è quello che farei, se lo volessi per la base 10. È abbastanza veloce e non otterrai uno stack overclock comprando numeri interi


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

Se più veloce è più efficiente, questo è un miglioramento rispetto al miglioramento di andrei alexandrescu . La sua versione era già più veloce del modo ingenuo (dividendo per 10 ad ogni cifra). La versione seguente è a tempo costante e più veloce almeno su x86-64 e ARM per tutte le dimensioni, ma occupa il doppio del codice binario, quindi non è così intuitivo per la cache.

Benchmark per questa versione vs la versione di alexandrescu sul mio PR su follia di Facebook .

Funziona 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

Stavo lavorando a un programma che mi richiedeva di verificare se l'utente aveva risposto correttamente a quante cifre c'erano in un numero, quindi ho dovuto sviluppare un modo per controllare la quantità di cifre in un numero intero. Alla fine è stata una cosa relativamente facile da risolvere.

double check=0, exponent=1000;

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

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

Questa è stata la mia risposta che attualmente funziona con numeri con meno di 10 ^ 1000 cifre (può essere modificato cambiando il valore dell'esponente).

PS So che questa risposta è in ritardo di dieci anni, ma sono arrivata qui nel 2020, quindi altre persone potrebbero 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);
    }
};

dove powers_and_maxabbiamo (10^n)-1per tutto nciò che

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

e std::numeric_limits<type>::max()in un array:

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());
   }
};

ecco un semplice test:

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);

Ovviamente qualsiasi altra implementazione di un set ordinato potrebbe essere utilizzata per powers_and_maxe se ci fosse la conoscenza che ci sarebbe un clustering ma nessuna conoscenza di dove potrebbe essere il cluster forse un'implementazione dell'albero autoregolante potrebbe essere la migliore


-1

modo effettivo

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

Aggiornamento C ++ 11 della soluzione preferita:

#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;
        }

impedisce l'istanza del modello con double, et. al.


-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

Questo è il mio modo di farlo:

   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
mentre la sindrome di true / break: D
Петър Петров

-1 questo è lo stesso approccio che la prima risposta ha dato sei anni prima e non aggiunge nulla (in effetti è significativamente peggiore).

-4

Ecco un approccio diverso:

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

Questo potrebbe non essere efficiente, solo qualcosa di diverso da quello che altri hanno suggerito.


4
La richiesta era estremamente efficiente. Questo è l'opposto.
Ira Baxter,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.