tags:

views:

484

answers:

11

Hello,

I would like to know how I can find the length of an integer in C.

For instance:

  • 1 => 1
  • 25 => 2
  • 12512 => 5
  • 0 => 1

etc.

How can I do this in C?

+1  A: 

Yes, using sprintf.

int num;
scanf("%d",&num);
char testing[100];
sprintf(testing,"%d",num);
int length = strlen(testing);

Alternatively, you can do this mathematically using the log10 function.

int num;
scanf("%d",&num);
int length;
if (num == 0) {
  length = 1;
} else {    
  length = log10(fabs(num)) + 1;
  if (num < 0) length++;
}
Jamie Wong
No, that's actually rather dangerous and prone to errors. You should use `snprintf()` so you don't have to write (and risk overflowing) anything.
Chris Lutz
Assuming he was referring to a C integer (not a bignum type) there won't be any issues with overflows.
Jamie Wong
@phleet - There will be issues when computers get bigger. Sure, you'll need a 512 bit computer to break your code, but they'll probably make one someday.
Chris Lutz
no, likely 128 bit will be the last frontier... there won't be any reason to go beyond (exagerating, I say there's no reason for going beyond 64 bits, but I am _almost_ already wrong, but currently no real 128bit processor are available yet, and they hardly will be, at least in consumer computing... I hope, since the they will need them, it would mean O.S. will be too fat and we'll remember these days as better days)
ShinTakezou
A: 

Quite simple

int main() {
    int num = 123;
    char buf[50];

    // convert 123 to string [buf]
    itoa(num, buf, 10);

    // print our string
    printf("%s\n", strlen (buf));

    return 0;
}
Mauro
`itoa()` isn't standard C.
Chris Lutz
Sure, Thx for the comment
Mauro
it can be easily written however
ShinTakezou
+9  A: 
int get_int_len (int value){
  int l=1;
  while(value>9){ l++; value/=10; }
  return l;
}

and second one will work for negative numbers too:

int get_int_len_with_negative_too (int value){
  int l=!value;
  while(value){ l++; value/=10; }
  return l;
}
zed_0xff
I like this. No temporary character buffers with assumptions about the size.
Noufal Ibrahim
Quick and elegant, however, this won't work for negative numbers. Don't know if that's a concern for the question poster
Jamie Wong
my answer is similar but works for negative numbers
Graphics Noob
updated to work with negative too
zed_0xff
The second version won't work for 0.
Eamon Nerbonne
it will. give it a try. it will return 1
zed_0xff
You're right - it will indeed :-). It'd be clearer to me (and no slower) to distinguish that case via an if-return rather than a negation.
Eamon Nerbonne
+6  A: 

You can write a function like this:

unsigned numDigits(const unsigned n) {
    if (n < 10) return 1;
    return 1 + numDigits(n / 10);
}
Kangkan
This is unnecessarily inefficient - why use up to around 18 recursive function calls when you can do it with one call to log10?
Jordan Lewis
but making it not recursive could be in some circumstances, depending on the cpus and availability of float coprocessor, faster than using a fuction like log10
ShinTakezou
@Jordan Lewis calling this 20 million times takes 1.8s on my netbook; calling your code takes 6.6 seconds (gcc -O3 for both). One call to log10 is very much slower than all the recursive calls this makes.
Pete Kirkham
@Pete I see .001s for the log10 version and .44s for the recursive version on my Intel i7, for 20 million times with -O3.
Jordan Lewis
Simple recursive form. I like it.
Cheery
@Jordan are you calling it with the same or different values?` int c = 0; for ( int i = -10000000; i < 10000000; ++i ) c += printed_length(i); printf ( "total %d\n", c);`
Pete Kirkham
@Pete I was iterating from i = 0 to 2 million, and using i as the parameter to printed_length as well. I will try again with your parameters, including the +=.
Jordan Lewis
Well, surely you weren't using this numDigits implementation for the negative values, as it doesn't handle negative values?
Jordan Lewis
@Pete and @Jordan thanks for bringing in the context of efficiency. I proposed my answer looking at the simplicity.
Kangkan
@Jordan I added `if ( x < 0 ) return 1 + printed_length ( -x );` to the start of it
Pete Kirkham
@Pete I must have made a mistake causing the compiler to optimize out the actual calls before. I now observe a gap like yours - .26 seconds for the recursive version, and 1.68 seconds for the floating point arithmetic version. Interesting!
Jordan Lewis
Quite possibly the recursive version is less recursive that it looks once compiled - depending on version/options, gcc will partially unroll short recursive calls like this; that's particularly easy here since it's a tail call.
Eamon Nerbonne
+1 for the easiest to understand code.
Eamon Nerbonne
@Eamon Nerbonne the `1 + ` part stops it being a trivial tail call.
Pete Kirkham
@Pete: indeed; not trivial; still inlinable though; and with a maximum depth of a dozen or so inlining would work well.
Eamon Nerbonne
A: 

keep dividing by ten until you get zero, then just output the number of divisions.

int intLen(int x)
{
  if(!x) return 1;
  int i;
  for(i=0; x!=0; ++i)
  {
    x /= 10;
  }
  return i;
}
Graphics Noob
This is incorrect. This will return an arbitrary number if x = 0.
Jamie Wong
Bet it won't... It will however return the wrong value for 0.
Blindy
@phleet, I'm pretty sure the semicolon after i=0 is a sequence point, but zero is still the wrong output. It's fixed now though.
Graphics Noob
+18  A: 

Why not just take the base-10 log of the absolute value of the number, round it down, and add one? This works for positive and negative numbers that aren't 0, and avoids having to use any string conversion functions.

The log10, abs, and floor functions are provided by math.h. For example:

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

You should wrap this in a clause ensuring that the_integer != 0, since log10(0) returns -HUGE_VAL according to man 3 log.

Additionally, you may want to add one to the final result if the input is negative, if you're interested in the length of the number including its negative sign.


N.B. The floating-point nature of the calculations involved in this method may cause it to be slower than a more direct approach. See the comments for Kangkan's answer for some discussion of efficiency.

Jordan Lewis
Technically you want `floor`, not `ceil`. `ceil(log10(10))=1`, while `floor(log10(10)+1)=2`.
Blindy
Actually you should use floor and add 1 instead. Math.Ceil(Math.Log(99)) = 2 but Math.Ceil(Math.Log(10)) = 1. Math.Floor(Math.Log(99)) + 1 = 2 and Math.Floor(Math.Log(10)) = 2
Sani Huttunen
Thanks; I've edited my answer.@Sani, you missed a +1 in your second example there.
Jordan Lewis
The question isn't entirely clear on the definition of length (so you could possibly have thought 'number of digits excluding leading zeros'), but I would expect 0 and -1 to return 1 and 2 as the length of their character representation rather than -2147483648 and 1.
Pete Kirkham
@Pete Thanks for reminding me about log's domain limitation and the negative number case - I've edited my answer.
Jordan Lewis
+1. Every programmer should know basic math.
el.pescado
Eamon Nerbonne
+2  A: 

The number of digits of an integer x is equal to 1 + log10(x). So you can do this:

#include <math.h>
#include <stdio.h>

int main()
{
    int x;
    scanf("%d", &x);
    printf("x has %d digits\n", 1 + (int)log10(x));
}

Or you can run a loop to count the digits yourself: do integer division by 10 until the number is 0:

int numDigits = 0;
do
{
    ++numDigits;
    x = x / 10;
} while ( x );

You have to be a bit careful to return 1 if the integer is 0 in the first solution and you might also want to treat negative integers (work with -x if x < 0).

IVlad
+4  A: 

length of n:

length =  (int)log10(n)+1;
fgm
You should probably avoid rounding via casting and instead go or a more explicit (a.k.a. portable and consistent) rounding approach.
Chris Lutz
how is `casting` implemented? how a function like floor can be implemented? (we are assuming a processor with ieee in hardware, or through a math coprocessor, or the availability of software function to perform the same function normally present on fp-capable processors)... at the end (int) is portable and consistent in most cases (I dare say, all the cases we normally care of)
ShinTakezou
As mentioned in other posts, this will fail when n = 0
Jamie Wong
@Lutz: what kind of portability are you buying by assuming casting from double to int is undefined? Is there actually a relevant platform where this is the case?
Eamon Nerbonne
@Chris Lutz If it's a standards compliant C implementation, then it obeys *When a finite value of real floating type is converted to an integer type other than _Bool, the fractional part is discarded (i.e., the value is truncated toward zero).*
Pete Kirkham
@Pete, @Eamon - My bad. I thought it was undefined or implementation defined.
Chris Lutz
+3  A: 

The most efficient way could possibly be to use a fast logarithm based approach, similar to those used to determine the highest bit set in an integer.

size_t printed_length ( int32_t x )
{
    size_t count = x < 0 ? 2 : 1;

    if ( x < 0 ) x = -x;

    if ( x >= 100000000 ) {
        count += 8;
        x /= 100000000;
    }

    if ( x >= 10000 ) {
        count += 4;
        x /= 10000;
    }

    if ( x >= 100 ) {
        count += 2;
        x /= 100;
    }

    if ( x >= 10 )
        ++count;

    return count;
}

This (possibly premature) optimisation takes 0.65s for 20 million calls on my netbook; iterative division like zed_0xff has takes 1.6s, recursive division like Kangkan takes 1.8s, and using floating point functions (Jordan Lewis' code) takes a whopping 6.6s. Using snprintf takes 11.5s, but will give you the size that snprintf requires for any format, not just integers. Jordan reports that the ordering of the timings are not maintained on his processor, which does floating point faster than mine.

The easiest is probably to ask snprintf for the printed length:

#include <stdio.h>

size_t printed_length ( int x )
{
    return snprintf ( NULL, 0, "%d", x );
}

int main ()
{
    int x[] = { 1, 25, 12512, 0, -15 };

    for ( int i = 0; i < sizeof ( x ) / sizeof ( x[0] ); ++i )
        printf ( "%d -> %d\n", x[i], printed_length ( x[i] ) );

    return 0;
}
Pete Kirkham
If you're going to use `snprintf()`, why not `snprintf(NULL, 0, "%d", x)` and not write anything? (At the very least, use a static buffer in your function.)
Chris Lutz
because I haven't had enough coffee yet this morning, and was thinking about the first leg of the answer.
Pete Kirkham
Should split your replies in two posts, I'd +1 the first one but not the 2nd.
Blindy
It rather depends why you want the length - if you want to know how many chars snprintf will require, you're better off using snprintf; if you want silly optimised code, you might want the first one.
Pete Kirkham
" C99 allows str to be NULL in this case [the case of n==0], and gives the return value (as always) as the number of characters that would have been written in case the output string has been large enough" so it is ok, why not
ShinTakezou
(Ah... I suppose the answer was modified, following Lutz's suggestion... ?)
ShinTakezou
@ShinTakezou yes.
Pete Kirkham
A: 

sprintf(s, "%d", n); length_of_int = strlen(s);

OK_or_CANCEL
+6  A: 

If you're interested in a fast and very simple solution, the following might be quickest (this depends on the probability distribution of the numbers in question):

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

int printLen(int x) {
    return x<0 ? lenHelper(-x)+1 : lenHelper(x);
}

While it might not win prizes for the most ingenious solution, it's trivial to understand and also trivial to execute - so it's fast.

On a Q6600 using MSC I benchmarked this with the following loop:

int res=0;
for(int i=-2000000000;i<2000000000;i+=200) res+=printLen(i);

This solution takes 0.062s, the second-fastest solution by Pete Kirkham using a smart-logarithm approach takes 0.115s - almost twice as long. However, for numbers around 10000 and below, the smart-log is faster.

At the expense of some clarity, you can more reliably beat smart-log (at least, on a Q6600):

int lenHelper(unsigned x) { 
    // this is either a fun exercise in optimization 
    // or it's extremely premature optimization.
    if(x>=100000) {
        if(x>=10000000) {
            if(x>=1000000000) return 10;
            if(x>=100000000) return 9;
            return 8;
        }
        if(x>=1000000) return 7;
        return 6;
    } else {
        if(x>=1000) {
            if(x>=10000) return 5;
            return 4;
        } else {
            if(x>=100) return 3;
            if(x>=10) return 2;
            return 1;
        }
    }
}

This solution is still 0.062s on large numbers, and degrades to around 0.09s for smaller numbers - faster in both cases than the smart-log approach. (gcc makes faster code; 0.052 for this solution and 0.09s for the smart-log approach).

Eamon Nerbonne
I shudder to think what the second version would look like written entirely with the ternary operator...
Eamon Nerbonne