How do I determine the number of digits of an integer in C? How do I determine the number of digits of an integer in C? c c

How do I determine the number of digits of an integer in C?


The recursive approach :-)

int numPlaces (int n) {    if (n < 0) return numPlaces ((n == INT_MIN) ? INT_MAX: -n);    if (n < 10) return 1;    return 1 + numPlaces (n / 10);}

Or iterative:

int numPlaces (int n) {    int r = 1;    if (n < 0) n = (n == INT_MIN) ? INT_MAX: -n;    while (n > 9) {        n /= 10;        r++;    }    return r;}

Or raw speed:

int numPlaces (int n) {    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;    if (n < 10) return 1;    if (n < 100) return 2;    if (n < 1000) return 3;    if (n < 10000) return 4;    if (n < 100000) return 5;    if (n < 1000000) return 6;    if (n < 10000000) return 7;    if (n < 100000000) return 8;    if (n < 1000000000) return 9;    /*      2147483647 is 2^31-1 - add more ifs as needed       and adjust this final return as well. */    return 10;}

Those above have been modified to better process MININT. On any weird systems that don't follow sensible 2n two's complement rules for integers, they may need further adjustment.

The raw speed version actually outperforms the floating point version, modified below:

int numPlaces (int n) {    if (n == 0) return 1;    return floor (log10 (abs (n))) + 1;}

With a hundred million iterations, I get the following results:

Raw speed with 0:            0 secondsRaw speed with 2^31-1:       1 secondIterative with 2^31-1:       5 secondsRecursive with 2^31-1:       6 secondsFloating point with 1:       6 secondsFloating point with 2^31-1:  7 seconds

That actually surprised me a little - I thought the Intel chips had a decent FPU but I guess general FP operations still can't compete with hand-optimized integer code.

Update following stormsoul's suggestions:

Testing the multiply-iterative solution by stormsoul gives a result of 4 seconds so, while it's much faster than the divide-iterative solution, it still doesn't match the optimized if-statement solution.

Choosing the arguments from a pool of 1000 randomly generated numbers pushed the raw speed time out to 2 seconds so, while it appears there may have been some advantage to having the same argument each time, it's still the fastest approach listed.

Compiling with -O2 improved the speeds but not the relative positions (I increased the iteration count by a factor of ten to check this).

Any further analysis is going to have to get seriously into the inner workings of CPU efficiency (different types of optimization, use of caches, branch prediction, which CPU you actually have, the ambient temperature in the room and so on) which is going to get in the way of my paid work :-). It's been an interesting diversion but, at some point, the return on investment for optimization becomes too small to matter. I think we've got enough solutions to have answered the question (which was, after all, not about speed).

Further update:

This will be my final update to this answer barring glaring errors that aren't dependent on architecture. Inspired by stormsoul's valiant efforts to measure, I'm posting my test program (modified as per stormsoul's own test program) along with some sample figures for all methods shown in the answers here. Keep in mind this is on a particular machine, your mileage may vary depending on where you run it (which is why I'm posting the test code).

Do with it as you wish:

#include <stdio.h>#include <stdlib.h>#include <math.h>#include <limits.h>#include <time.h>#define numof(a) (sizeof(a) / sizeof(a[0]))/* Random numbers and accuracy checks. */static int rndnum[10000];static int rt[numof(rndnum)];/* All digit counting functions here. */static int count_recur (int n) {    if (n < 0) return count_recur ((n == INT_MIN) ? INT_MAX : -n);    if (n < 10) return 1;    return 1 + count_recur (n / 10);}static int count_diviter (int n) {    int r = 1;    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;    while (n > 9) {        n /= 10;        r++;    }    return r;}static int count_multiter (int n) {    unsigned int num = abs(n);    unsigned int x, i;    for (x=10, i=1; ; x*=10, i++) {        if (num < x)            return i;        if (x > INT_MAX/10)            return i+1;    }}static int count_ifs (int n) {    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;    if (n < 10) return 1;    if (n < 100) return 2;    if (n < 1000) return 3;    if (n < 10000) return 4;    if (n < 100000) return 5;    if (n < 1000000) return 6;    if (n < 10000000) return 7;    if (n < 100000000) return 8;    if (n < 1000000000) return 9;    /*      2147483647 is 2^31-1 - add more ifs as needed    and adjust this final return as well. */    return 10;}static int count_revifs (int n) {    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;    if (n > 999999999) return 10;    if (n > 99999999) return 9;    if (n > 9999999) return 8;    if (n > 999999) return 7;    if (n > 99999) return 6;    if (n > 9999) return 5;    if (n > 999) return 4;    if (n > 99) return 3;    if (n > 9) return 2;    return 1;}static int count_log10 (int n) {    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;    if (n == 0) return 1;    return floor (log10 (n)) + 1;}static int count_bchop (int n) {    int r = 1;    if (n < 0) n = (n == INT_MIN) ? INT_MAX : -n;    if (n >= 100000000) {        r += 8;        n /= 100000000;    }    if (n >= 10000) {        r += 4;        n /= 10000;    }    if (n >= 100) {        r += 2;        n /= 100;    }    if (n >= 10)        r++;    return r;}/* Structure to control calling of functions. */typedef struct {    int (*fnptr)(int);    char *desc;} tFn;static tFn fn[] = {    NULL,                              NULL,    count_recur,    "            recursive",    count_diviter,  "     divide-iterative",    count_multiter, "   multiply-iterative",    count_ifs,      "        if-statements",    count_revifs,   "reverse-if-statements",    count_log10,    "               log-10",    count_bchop,    "          binary chop",};static clock_t clk[numof (fn)];int main (int c, char *v[]) {    int i, j, k, r;    int s = 1;    /* Test code:        printf ("%11d %d\n", INT_MIN, count_recur(INT_MIN));        for (i = -1000000000; i != 0; i /= 10)            printf ("%11d %d\n", i, count_recur(i));        printf ("%11d %d\n", 0, count_recur(0));        for (i = 1; i != 1000000000; i *= 10)            printf ("%11d %d\n", i, count_recur(i));        printf ("%11d %d\n", 1000000000, count_recur(1000000000));        printf ("%11d %d\n", INT_MAX, count_recur(INT_MAX));    /* */    /* Randomize and create random pool of numbers. */    srand (time (NULL));    for (j = 0; j < numof (rndnum); j++) {        rndnum[j] = s * rand();        s = -s;    }    rndnum[0] = INT_MAX;    rndnum[1] = INT_MIN;    /* For testing. */    for (k = 0; k < numof (rndnum); k++) {        rt[k] = (fn[1].fnptr)(rndnum[k]);    }    /* Test each of the functions in turn. */    clk[0] = clock();    for (i = 1; i < numof (fn); i++) {        for (j = 0; j < 10000; j++) {            for (k = 0; k < numof (rndnum); k++) {                r = (fn[i].fnptr)(rndnum[k]);                /* Test code:                    if (r != rt[k]) {                        printf ("Mismatch error [%s] %d %d %d %d\n",                            fn[i].desc, k, rndnum[k], rt[k], r);                        return 1;                    }                /* */            }        }        clk[i] = clock();    }    /* Print out results. */    for (i = 1; i < numof (fn); i++) {        printf ("Time for %s: %10d\n", fn[i].desc, (int)(clk[i] - clk[i-1]));    }    return 0;}

Remember that you need to ensure you use the correct command line to compile it. In particular, you may need to explicitly list the math library to get log10() working. The command line I used under Debian was gcc -o testprog testprog.c -lm.

And, in terms of results, here's the leader-board for my environment:

Optimization level 0:

Time for reverse-if-statements:       1704Time for         if-statements:       2296Time for           binary chop:       2515Time for    multiply-iterative:       5141Time for      divide-iterative:       7375Time for             recursive:      10469Time for                log-10:      26953

Optimization level 3:

Time for         if-statements:       1047Time for           binary chop:       1156Time for reverse-if-statements:       1500Time for    multiply-iterative:       2937Time for      divide-iterative:       5391Time for             recursive:       8875Time for                log-10:      25438


Binary search pseudo algorithm to get no of digits of r in v..

if (v < 0 ) v=-v;r=1;if (v >= 100000000){  r+=8;  v/=100000000;}if (v >= 10000) {    r+=4;    v/=10000;}if (v >= 100) {    r+=2;    v/=100;}if( v>=10){    r+=1;}return r;