How can you get the first digit in an int (C#)?

Viewed 121189

In C#, what's the best way to get the 1st digit in an int? The method I came up with is to turn the int into a string, find the 1st char of the string, then turn it back to an int.

int start = Convert.ToInt32(curr.ToString().Substring(0, 1));

While this does the job, it feels like there is probably a good, simple, math-based solution to such a problem. String manipulation feels clunky.

Edit: irrespective of speed differences, mystring[0] instead of Substring() is still just string manipulation

25 Answers

Benchmarks

Firstly, you must decide on what you mean by "best" solution, of course that takes into account the efficiency of the algorithm, its readability/maintainability, and the likelihood of bugs creeping up in the future. Careful unit tests can generally avoid those problems, however.

I ran each of these examples 10 million times, and the results value is the number of ElapsedTicks that have passed.

Without further ado, from slowest to quickest, the algorithms are:

Converting to a string, take first character

int firstDigit = (int)(Value.ToString()[0]) - 48;

Results:

12,552,893 ticks

Using a logarithm

int firstDigit = (int)(Value / Math.Pow(10, (int)Math.Floor(Math.Log10(Value))));

Results:

9,165,089 ticks

Looping

while (number >= 10)
    number /= 10;

Results:

6,001,570 ticks

Conditionals

int firstdigit;
if (Value < 10)
     firstdigit = Value;
else if (Value < 100)
     firstdigit = Value / 10;
else if (Value < 1000)
     firstdigit = Value / 100;
else if (Value < 10000)
     firstdigit = Value / 1000;
else if (Value < 100000)
     firstdigit = Value / 10000;
else if (Value < 1000000)
     firstdigit = Value / 100000;
else if (Value < 10000000)
     firstdigit = Value / 1000000;
else if (Value < 100000000)
     firstdigit = Value / 10000000;
else if (Value < 1000000000)
     firstdigit = Value / 100000000;
else
     firstdigit = Value / 1000000000;

Results:

1,421,659 ticks

Unrolled & optimized loop

if (i >= 100000000) i /= 100000000;
if (i >= 10000) i /= 10000;
if (i >= 100) i /= 100;
if (i >= 10) i /= 10;

Results:

1,399,788 ticks

Note:

each test calls Random.Next() to get the next int

Here's how

int i = Math.Abs(386792);
while(i >= 10)
    i /= 10;

and i will contain what you need

Try this

public int GetFirstDigit(int number) {
  if ( number < 10 ) {
    return number;
  }
  return GetFirstDigit ( (number - (number % 10)) / 10);
}

EDIT

Several people have requested the loop version

public static int GetFirstDigitLoop(int number)
{
    while (number >= 10)
    {
        number = (number - (number % 10)) / 10;
    }
    return number;
}

The best I can come up with is:

int numberOfDigits = Convert.ToInt32(Math.Floor( Math.Log10( value ) ) );

int firstDigit = value / Math.Pow( 10, numberOfDigits );

variation on Anton's answer:

 // cut down the number of divisions (assuming i is positive & 32 bits)
if (i >= 100000000) i /= 100000000;
if (i >= 10000) i /= 10000;
if (i >= 100) i /= 100;
if (i >= 10) i /= 10;
int myNumber = 8383;
char firstDigit = myNumber.ToString()[0];
// char = '8'

Had the same idea as Lennaert

int start = number == 0 ? 0 : number / (int) Math.Pow(10,Math.Floor(Math.Log10(Math.Abs(number))));

This also works with negative numbers.

If you think Keltex's answer is ugly, try this one, it's REALLY ugly, and even faster. It does unrolled binary search to determine the length.

 ... leading code along the same lines
/* i<10000 */
if (i >= 100){
  if (i >= 1000){
    return i/1000;
  }
  else /* i<1000 */{
    return i/100;
  }
}
else /* i<100*/ {
  if (i >= 10){
    return i/10;
  }
  else /* i<10 */{
    return i;
  }
}

P.S. MartinStettner had the same idea.

Very simple (and probably quite fast because it only involves comparisons and one division):

if(i<10)
   firstdigit = i;
else if (i<100)
   firstdigit = i/10;
else if (i<1000)
   firstdigit = i/100;
else if (i<10000)
   firstdigit = i/1000;
else if (i<100000)
   firstdigit = i/10000;
else (etc... all the way up to 1000000000)
int temp = i;
while (temp >= 10)
{
    temp /= 10;
}

Result in temp

An obvious, but slow, mathematical approach is:

int firstDigit = (int)(i / Math.Pow(10, (int)Math.Log10(i))));

I know it's not C#, but it's surprising curious that in python the "get the first char of the string representation of the number" is the faster!

EDIT: no, I made a mistake, I forgot to construct again the int, sorry. The unrolled version it's the fastest.

$ cat first_digit.py
def loop(n):
    while n >= 10:
        n /= 10
    return n

def unrolled(n):
    while n >= 100000000: # yea... unlimited size int supported :)
        n /= 100000000
    if n >= 10000:
        n /= 10000
    if n >= 100:
        n /= 100
    if n >= 10:
        n /= 10
    return n

def string(n):
    return int(str(n)[0])
$ python -mtimeit -s 'from first_digit import loop as test' \
    'for n in xrange(0, 100000000, 1000): test(n)'
10 loops, best of 3: 275 msec per loop
$ python -mtimeit -s 'from first_digit import unrolled as test' \
    'for n in xrange(0, 100000000, 1000): test(n)'
10 loops, best of 3: 149 msec per loop
$ python -mtimeit -s 'from first_digit import string as test' \
    'for n in xrange(0, 100000000, 1000): test(n)'
10 loops, best of 3: 284 msec per loop
$

Did some tests with one of my co-workers here, and found out most of the solutions don't work for numbers under 0.

  public int GetFirstDigit(int number)
    {
        number = Math.Abs(number); <- makes sure you really get the digit!

        if (number < 10)
        {
            return number;
        }
        return GetFirstDigit((number - (number % 10)) / 10);
    }

Check this one too:

int get1digit(Int64 myVal)
{
    string q12 = myVal.ToString()[0].ToString();
    int i = int.Parse(q12);
    return i;
}

Also good if you want multiple numbers:

int get3digit(Int64 myVal) //Int64 or whatever numerical data you have
{
    char mg1 = myVal.ToString()[0];
    char mg2 = myVal.ToString()[1];
    char mg3 = myVal.ToString()[2];
    char[] chars = { mg1, mg2, mg3 };
    string q12= new string(chars);
    int i = int.Parse(q12);
    return i;
}

Just to give you an alternative, you could repeatedly divide the integer by 10, and then rollback one value once you reach zero. Since string operations are generally slow, this may be faster than string manipulation, but is by no means elegant.

Something like this:

while(curr>=10)
     curr /= 10;
while (i > 10)
{
   i = (Int32)Math.Floor((Decimal)i / 10);
}
// i is now the first int
start = getFirstDigit(start);   
public int getFirstDigit(final int start){
    int number = Math.abs(start);
    while(number > 10){
        number /= 10;
    }
    return number;
}

or

public int getFirstDigit(final int start){
  return getFirstDigit(Math.abs(start), true);
}
private int getFirstDigit(final int start, final boolean recurse){
  if(start < 10){
    return start;
  }
  return getFirstDigit(start / 10, recurse);
}
int start = curr;
while (start >= 10)
  start /= 10;

This is more efficient than a ToString() approach which internally must implement a similar loop and has to construct (and parse) a string object on the way ...

Non iterative formula:

public static int GetHighestDigit(int num)
{
    if (num <= 0)
       return 0; 

    return (int)((double)num / Math.Pow(10f, Math.Floor(Math.Log10(num))));
}

Here is a simpler way that does not involve looping

int number = 1234
int firstDigit = Math.Floor(number/(Math.Pow(10, number.ToString().length - 1))

That would give us 1234/Math.Pow(10, 4 - 1) = 1234/1000 = 1

Related