views:

256

answers:

6

In .NET what is the best way to find the length of an integer in characters if it was represented as a string?

e.g.

1 = 1 character
10 = 2 characters
99 = 2 characters
100 = 3 characters
1000 = 4 characters

The obvious answer is to convert the int to a string and get its length but I want the best performance possible without the overhead of creating a new string.

+2  A: 

You could use something like this:

        int integer = 100;

        int charachtersCount = 0;
        while (integer > 0)
        {
            integer = integer/10;
            charachtersCount++;
        }

But do you really need to optimize this? I would actually prefer using string (looks much better):

integer.ToString().Length
Andrew Bezzub
Nice solution, but as you said I would doubt that the performance is good. I guess that string conversion is best.
Simon Linder
+27  A: 

you can use logartihms to calculate the length of the int:

public static int IntLength(int i) {
  if (i <= 0) throw new ArgumentOutOfRangeException();

  return (int)Math.Floor(Math.Log10(i)) + 1;
}

the test passes:

[Test]
public void TestIntLength() {
  Assert.AreEqual(1, IntLength(1));
  Assert.AreEqual(1, IntLength(9));
  Assert.AreEqual(2, IntLength(10));
  Assert.AreEqual(2, IntLength(99));
  Assert.AreEqual(3, IntLength(100));
  Assert.AreEqual(3, IntLength(999));
  Assert.AreEqual(4, IntLength(1000));
  Assert.AreEqual(10, IntLength(int.MaxValue));
}

a quick test has shown that the log-method is 4 times faster than the int.ToString().Length method..

the method shown by GvS below (using if-statements) is another 6 times (!) faster than the log method:

public static int IntLengthIf(int i) {
  if (i < 10) return 1;
  if (i < 100) return 2;
  if (i < 1000) return 3;
  if (i < 10000) return 4;
  if (i < 100000) return 5;
  if (i < 1000000) return 6;
  if (i < 10000000) return 7;
  if (i < 100000000) return 8;
  if (i < 1000000000) return 9;
  throw new ArgumentOutOfRangeException();
}

here are the exact timings for the numbers 1 to 10000000:

IntLengthToString: 4205ms
IntLengthLog10: 1122ms
IntLengthIf: 201ms
stmax
To cope with negative numbers, you could get the absolute value of i and then add 1 to the result of the function.
Matt Ellen
If you have a quick test for this already, you should compare it to GvS's solution. That should be interesting.
Jeffrey L Whitledge
i have updated my answer. GvS's method is much faster.
stmax
A: 

If you want to do it by maths you could try this:

int integer = 100
int charCount = (int) Math.Ceiling(Math.Log10(integer+1));

I doubt if this is very much faster than converting to a string though

Rik
+1  A: 

If you need to deal with negative numbers also, you can take stmax solution with a spin:

public static int IntLength(int i) { 
  if (i == 0) return 1; // no log10(0)
  int n = (i < 0) ? 2 : 1;
  i = (i < 0) ? -i : i;

  return (int)Math.Floor(Math.Log10(i)) + n; 
} 
Paulo Santos
+9  A: 

If input is in range 0-10000

if (i < 10) return 1;
if (i < 100) return 2;
if (i < 1000) return 3;
if (i < 10000) return 4;
// etc
GvS
This is the simplest solution, and it reads well. It probably can't compete with an optimized floating point logarithm.
GregS
I am not going to bother doing the test, but I bet this solution is faster than the logarithm one. Logs take quite a few clock cycles to compute.
Jeffrey L Whitledge
it's 6x faster than my method using logs.
stmax
A: 

You can do:

int ndig = 1;
if (n < 0){n = -n; ndig++;}
if (n >= 100000000){n /= 100000000; ndig += 8;}
if (n >=     10000){n /=     10000; ndig += 4;}
if (n >=       100){n /=       100; ndig += 2;}
if (n >=        10){n /=        10; ndig += 1;}

or something along those lines. It takes 4 comparisons and 0-4 divisions.

(On 64 bits you have to add a fifth level.)

Mike Dunlavey