19

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.

6
  • 9
    Always balance the free microseconds you are attempting to gain against the expensive reading time of the poor sucker (yourself, I guess) who has to read and debug that code later on. Commented Mar 24, 2010 at 9:38
  • 4
    @reinierpost it's not a micro-optimization if the said method is run, like, a billion times in a loop called by thousands of different threads. Commented Mar 24, 2010 at 9:47
  • Duplicate of this one? stackoverflow.com/questions/679602/… Commented Mar 24, 2010 at 10:04
  • If the performance of conversion to base 10 is an issue, then you should consider direct decimal representations, such as BCD, for your integers. This conversion penalty is one reason why calculators and early CPUs had BCD arithemetic. Commented Mar 24, 2010 at 13:47
  • @GregS - I suspect that it's not the conversion itself that's the problem, but rather filling up the string heap with a lot of useless strings. Based on the way the GC works, however, I think that this also is not a problem in practice. Commented Mar 24, 2010 at 16:42

7 Answers 7

38

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
Sign up to request clarification or add additional context in comments.

4 Comments

To cope with negative numbers, you could get the absolute value of i and then add 1 to the result of the function.
If you have a quick test for this already, you should compare it to GvS's solution. That should be interesting.
you could add support for negative numbers: public static int IntLengthIf(int i, bool WithMinus) { int iCount = 0; if (i_iValue < 0) { i = -i; if (WithMinus) iCount++; } if (i_iValue < 10) iCount += 1; ...; return iCount;
By the way, there is a bug in IntLengthIf: if you have values > 1e9 like MAXINT, then you have 10 digits, but this case is not handled. So you should add if (i_iValue <= int.MaxValue) return 10;
12

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

2 Comments

This is the simplest solution, and it reads well. It probably can't compete with an optimized floating point logarithm.
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.
4

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

2 Comments

Nice solution, but as you said I would doubt that the performance is good. I guess that string conversion is best.
I would suspect that the performance here is quite good. It's using integer maths afterall.
1

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

Comments

1

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

1 Comment

This one gets clever points. It's slightly slower than the straight if but I like it.
0

Handles all ints, including 0, negative values and int.MinValue:

int GetFormattedLength(int i)
{
    return i == 0 ? 1 : (int)Math.Floor(Math.Log10(Math.Abs((double)i))) + (i > 0 ? 1 : 2);
}

And here's a version optimized for performance:

int GetFormattedLength(int i)
{
    if (i == 0)
        return 1;

    uint absI;
    int signLength = 0;
    if (i < 0)
    {
        absI = ((uint)~i) + 1;
        signLength = 1;
    }
    else
    {
        absI = (uint)i;
    }

    return absI switch
    {
        < 10 => 1,
        < 100 => 2,
        < 1000 => 3,
        < 10000 => 4,
        < 100000 => 5,
        < 1000000 => 6,
        < 10000000 => 7,
        < 100000000 => 8,
        < 1000000000 => 9,
        _ => 10,
    } + signLength;
}

Comments

-1

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.