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.

James Newton-King
  • 48,174
  • 24
  • 109
  • 130
  • 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. – reinierpost Mar 24 '10 at 09: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. – Paulo Santos Mar 24 '10 at 09:47
  • Duplicate of this one? http://stackoverflow.com/questions/679602/fastest-way-to-calculate-the-decimal-length-of-an-integer-net – Stefan Steinegger Mar 24 '10 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. – President James K. Polk Mar 24 '10 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. – Jeffrey L Whitledge Mar 24 '10 at 16:42
  • @GregS: Early machines also had BCD arithmetic because in business apps two things are intolerable: floating-point with binary conversion issues, and limited number length. – Mike Dunlavey Mar 24 '10 at 20:02

6 Answers6

37

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
  • 6,506
  • 4
  • 28
  • 45
  • 1
    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 Mar 24 '10 at 10:02
  • If you have a quick test for this already, you should compare it to GvS's solution. That should be interesting. – Jeffrey L Whitledge Mar 24 '10 at 16:48
  • 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; – Tobias Knauss Dec 15 '17 at 14:38
  • 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;` – Tobias Knauss Dec 15 '17 at 14:44
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
GvS
  • 52,015
  • 16
  • 101
  • 139
3

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
  • 15,744
  • 7
  • 51
  • 73
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; 
} 
Community
  • 1
  • 1
Paulo Santos
  • 11,285
  • 4
  • 39
  • 65
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.)

Mike Dunlavey
  • 40,059
  • 14
  • 91
  • 135
-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

Rik
  • 28,507
  • 14
  • 48
  • 67