Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

c

math

for instance,

n = 3432, result 4  n = 45, result 2  n = 33215, result 5  n = -357, result 3 

I guess I could just turn it into a string then get the length of the string but that seems convoluted and hack-y.

like image 624
willc2 Avatar asked Jul 01 '09 12:07

willc2


People also ask

How do you find the number of digits in an integer?

The formula will be integer of (log10(number) + 1). For an example, if the number is 1245, then it is above 1000, and below 10000, so the log value will be in range 3 < log10(1245) < 4. Now taking the integer, it will be 3. Then add 1 with it to get number of digits.

How do you count the no of digits in a number in C?

The number of digits can be calculated by using log10(num)+1, where log10() is the predefined function in math.

How do you find the number of digits?

To count number of digits divide the given number by 10 till number is greater than 0. For each iteration increment the value of some count variable. Step by step descriptive logic to count number of digits in given integer using loop.

What does count do in C?

This function is used to get the number of appearances of an element in the specified range. For example, if you want to find how many times 10 appears in the array [10,20,50,30,10,10,50,20,10], you can use the count() function instead of writing a loop to iterate over all the elements and then get the result.


2 Answers

floor (log10 (abs (x))) + 1 

http://en.wikipedia.org/wiki/Logarithm

like image 40
eduffy Avatar answered Oct 04 '22 15:10

eduffy


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 seconds Raw speed with 2^31-1:       1 second Iterative with 2^31-1:       5 seconds Recursive with 2^31-1:       6 seconds Floating point with 1:       6 seconds Floating 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:       1704 Time for         if-statements:       2296 Time for           binary chop:       2515 Time for    multiply-iterative:       5141 Time for      divide-iterative:       7375 Time for             recursive:      10469 Time for                log-10:      26953 

Optimization level 3:

Time for         if-statements:       1047 Time for           binary chop:       1156 Time for reverse-if-statements:       1500 Time for    multiply-iterative:       2937 Time for      divide-iterative:       5391 Time for             recursive:       8875 Time for                log-10:      25438 
like image 118
14 revs, 3 users 99% Avatar answered Oct 04 '22 17:10

14 revs, 3 users 99%