How can I get a count of the total number of digits of a number in C#? For example, the number 887979789 has 9 digits.
-
8try using .Length if it doesn't work convert it to a string first – Breezer Dec 19 '10 at 16:40
-
Let say x = 887979789; x.ToString().Count(); will give you that. – nPcomp Mar 22 '17 at 19:54
-
4I did some [PERFORMANCE TESTS on the best answers below to find out the FASTEST ONE](https://stackoverflow.com/questions/4483886/how-can-i-get-a-count-of-the-total-number-of-digits-in-a-number/51099524#51099524). – sɐunıɔןɐqɐp Jun 29 '18 at 10:29
18 Answers
Without converting to a string you could try
Math.Floor(Math.Log10(n) + 1);
-
15I'm afraid ceil(log10(10)) = ceil(1) = 1, and not 2 as it should be for this question! – ysap Dec 19 '10 at 18:08
-
6Thanks, it's a nice method. Though it's not any faster than int count = 0; do { count++; } while ((i /= 10) >= 1); :( – Puterdo Borato May 12 '12 at 18:25
-
3If your number range includes negatives, you'll need to use Math.Floor(Math.Log10(Math.Abs(n)) + 1); – mrcrowl Jun 06 '12 at 03:35
-
1Well if `n` is `0` can just return `1` :) Too handle negative values just replace `n` with `Math.Abs(n)`. – Umair Jun 13 '13 at 17:33
-
1Works a tiny bit faster if adding one after Math.Floor() because of 1 less operation on doubles. Works 26% faster (on my system) if Math.Floor() is replaced by casting to int: n == 0 ? 1 : (int)Math.Log10(Math.Abs(n)) + 1 – Sergii Bogomolov Jan 30 '15 at 07:38
-
3@Puterdo Borato: my performance test actually showed that your method is faster when the number of digits are < 5. Pass that, Steve's Math.floor is faster. – stack247 Apr 07 '15 at 22:56
-
@Steve: Log10 is quite tricky to get working correctly. Do you have any idea on how to implement it correctly for all range of possible input values? Please check my answer for the consistency tests. For `n = 0` this produces an error. – sɐunıɔןɐqɐp Dec 06 '19 at 15:57
-
6This does not work for 0. Math.Floor(Math.Log10(0) + 1) = -2147483648 (negative infiinity + 1). See https://learn.microsoft.com/en-us/dotnet/api/system.math.log10?view=netframework-4.8 documentation. – Idan P Apr 14 '20 at 08:48
-
-
To avoid erros with Log function for inputs less than or equal to zero, you must use this code: `return n == 0 ? 1 : (n > 0 ? 1 : 2) + (int)Math.Log10(Math.Abs((double)n));` - however this still generates precision errors for large numbers. See the other complete answer in this thread. – sɐunıɔןɐqɐp Oct 07 '21 at 14:19
-
This is more computationally intense than just converting it to a string, then getting the .Length – John Doe Aug 17 '22 at 03:43
-
@ John Doe: Unfortunately for the ones who prefer the string conversion simplicity, this statement is not true. Please see the performance test results in the other answer: the string conversion algorithm is one of the slowest ones in comparison with other well-implemented algorithms. You could also test the other alternatives by yourself, since the performance test code is provided in that answer. – sɐunıɔןɐqɐp Jul 04 '23 at 12:39
Try This:
myint.ToString().Length
Does that work ?

- 5,028
- 7
- 41
- 65

- 12,285
- 10
- 57
- 88
-
32It's worth pointing out that you'll likely run into problems with this method if you're dealing with negative numbers. (And obviously decimals, but the example uses an `int`, so I assume that's not an issue.) – Cody Gray - on strike Dec 19 '10 at 16:52
-
1I see code like this everywhere. Check out the performance tests on my answer. – sɐunıɔןɐqɐp Jun 29 '18 at 10:22
-
3@Krythic It's not the 1980s, your computer has enough RAM to save a 10 character string into memory for the duration of one operation. – MrLore Jul 17 '18 at 11:57
-
2@MrLore In simple applications this may be true, but in the game development world, it's an entirely different beast. – Krythic Jul 18 '18 at 01:00
There are 4 good possible solutions, but 1 of them is faster!
Any of the following extension methods will do the job. All of them consider the minus sign as a digit, and work correctly for all possible input values. They also work for .NET Framework and for .NET Core, .NET6. There are however relevant performance differences (discussed below), depending on your choice of Platform / Framework.
Int32 version:
public static class Int32Extensions
{
// IF-CHAIN:
public static int Digits_IfChain(this int n)
{
if (n >= 0)
{
if (n < 10) return 1;
if (n < 100) return 2;
if (n < 1000) return 3;
if (n < 10000) return 4;
if (n < 100000) return 5;
if (n < 1000000) return 6;
if (n < 10000000) return 7;
if (n < 100000000) return 8;
if (n < 1000000000) return 9;
return 10;
}
else
{
if (n > -10) return 2;
if (n > -100) return 3;
if (n > -1000) return 4;
if (n > -10000) return 5;
if (n > -100000) return 6;
if (n > -1000000) return 7;
if (n > -10000000) return 8;
if (n > -100000000) return 9;
if (n > -1000000000) return 10;
return 11;
}
}
// USING LOG10:
public static int Digits_Log10(this int n) =>
n == 0 ? 1 : (n > 0 ? 1 : 2) + (int)Math.Log10(Math.Abs((double)n));
// WHILE LOOP:
public static int Digits_While(this int n)
{
int digits = n < 0 ? 2 : 1;
while ((n /= 10) != 0) ++digits;
return digits;
}
// STRING CONVERSION:
public static int Digits_String(this int n) =>
n.ToString().Length;
}
Int64 version:
public static class Int64Extensions
{
// IF-CHAIN:
public static int Digits_IfChain(this long n)
{
if (n >= 0)
{
if (n < 10L) return 1;
if (n < 100L) return 2;
if (n < 1000L) return 3;
if (n < 10000L) return 4;
if (n < 100000L) return 5;
if (n < 1000000L) return 6;
if (n < 10000000L) return 7;
if (n < 100000000L) return 8;
if (n < 1000000000L) return 9;
if (n < 10000000000L) return 10;
if (n < 100000000000L) return 11;
if (n < 1000000000000L) return 12;
if (n < 10000000000000L) return 13;
if (n < 100000000000000L) return 14;
if (n < 1000000000000000L) return 15;
if (n < 10000000000000000L) return 16;
if (n < 100000000000000000L) return 17;
if (n < 1000000000000000000L) return 18;
return 19;
}
else
{
if (n > -10L) return 2;
if (n > -100L) return 3;
if (n > -1000L) return 4;
if (n > -10000L) return 5;
if (n > -100000L) return 6;
if (n > -1000000L) return 7;
if (n > -10000000L) return 8;
if (n > -100000000L) return 9;
if (n > -1000000000L) return 10;
if (n > -10000000000L) return 11;
if (n > -100000000000L) return 12;
if (n > -1000000000000L) return 13;
if (n > -10000000000000L) return 14;
if (n > -100000000000000L) return 15;
if (n > -1000000000000000L) return 16;
if (n > -10000000000000000L) return 17;
if (n > -100000000000000000L) return 18;
if (n > -1000000000000000000L) return 19;
return 20;
}
}
// USING LOG10:
public static int Digits_Log10(this long n) =>
n == 0L ? 1 : (n > 0L ? 1 : 2) + (int)Math.Log10(Math.Abs((double)n));
// WHILE LOOP:
public static int Digits_While(this long n)
{
int digits = n < 0 ? 2 : 1;
while ((n /= 10L) != 0L) ++digits;
return digits;
}
// STRING CONVERSION:
public static int Digits_String(this long n) =>
n.ToString().Length;
}
#Discussion#
This answer includes tests performed for both Int32
and Int64
types, using an array of 100.000.000
randomly sampled int
/ long
numbers. The random dataset is pre-processed into an array before executing the tests.
Consistency tests among the 4 different methods were also executed, for MinValue
, negative border cases, -1
, 0
, 1
, positive border cases, MaxValue
, and also for the whole random dataset. No consistency tests fail for the above provided methods, EXCEPT for the LOG10 method (this is discussed later).
The tests were executed on .NET Framework 4.7.2
and .NET Core 2.2
; for x86
and x64
platforms, on a 64-bit Intel Processor machine, with Windows 10
, and with VS2017 v.15.9.17
. The following 4 cases have the same effect on performance results:
.NET Framework (x86)
Platform = x86
Platform = AnyCPU
,Prefer 32-bit
is checked in project settings
.NET Framework (x64)
Platform = x64
Platform = AnyCPU
,Prefer 32-bit
is unchecked in project settings
.NET Core (x86)
"C:\Program Files (x86)\dotnet\dotnet.exe" bin\Release\netcoreapp2.2\ConsoleApp.dll
"C:\Program Files (x86)\dotnet\dotnet.exe" bin\x86\Release\netcoreapp2.2\ConsoleApp.dll
.NET Core (x64)
"C:\Program Files\dotnet\dotnet.exe" bin\Release\netcoreapp2.2\ConsoleApp.dll
"C:\Program Files\dotnet\dotnet.exe" bin\x64\Release\netcoreapp2.2\ConsoleApp.dll
#Results#
The performance tests below produce a uniform distribution of values among the wide range of values an integer could assume. This means there is a much higher chance of testing values with a big count of digits. In real life scenarios, most values may be small, so the IF-CHAIN should perform even better. Furthermore, the processor will cache and optimize the IF-CHAIN decisions according to your dataset.
As @AlanSingfield pointed out in the comment section, the LOG10 method had to be fixed with a casting to double
inside Math.Abs()
for the case when the input value is int.MinValue
or long.MinValue
.
Regarding the early performance tests I've implemented before editing this question (it had to be edited a million times already), there was a specific case pointed out by @GyörgyKőszeg, in which the IF-CHAIN method performs slower than the LOG10 method.
This still happens, although the magnitude of the difference became much lower after the fix for the issue pointed out by @AlanSingfield. This fix (adding a cast to double
) causes a computation error when the input value is exactly -999999999999999999
: the LOG10 method returns 20
instead of 19
. The LOG10 method also must have a if
guard for the case when the input value is zero.
The LOG10 method is quite tricky to get working for all values, which means you should avoid it. If someone finds a way to make it work correctly for all the consistency tests below, please post a comment!
The WHILE method also got a recent refactored version which is faster, but it is still slow for Platform = x86
(I could not find the reason why, until now).
The STRING method is consistently slow: it greedily allocates too much memory for nothing. Interestingly, in .NET Core, string allocation seems to be much faster than in .NET Framework. Good to know.
The IF-CHAIN method should outperform all other methods in 99.99% of the cases; and, in my personal opinion, is your best choice (considering all the adjusts necessary to make the LOG10 method work correctly, and the bad performance of the other two methods).
Finally, the results are:
Since these results are hardware-dependent, I recommend anyway running the performance tests below on your own computer if you really need to be 100% sure in your specific case.
#Test Code#
Below is the code for the performance test, and the consistency test too. The same code is used for both .NET Framework and .NET Core.
using System;
using System.Diagnostics;
namespace NumberOfDigits
{
// Performance Tests:
class Program
{
private static void Main(string[] args)
{
Console.WriteLine("\r\n.NET Core");
RunTests_Int32();
RunTests_Int64();
}
// Int32 Performance Tests:
private static void RunTests_Int32()
{
Console.WriteLine("\r\nInt32");
const int size = 100000000;
int[] samples = new int[size];
Random random = new Random((int)DateTime.Now.Ticks);
for (int i = 0; i < size; ++i)
samples[i] = random.Next(int.MinValue, int.MaxValue);
Stopwatch sw1 = new Stopwatch();
sw1.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_IfChain();
sw1.Stop();
Console.WriteLine($"IfChain: {sw1.ElapsedMilliseconds} ms");
Stopwatch sw2 = new Stopwatch();
sw2.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_Log10();
sw2.Stop();
Console.WriteLine($"Log10: {sw2.ElapsedMilliseconds} ms");
Stopwatch sw3 = new Stopwatch();
sw3.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_While();
sw3.Stop();
Console.WriteLine($"While: {sw3.ElapsedMilliseconds} ms");
Stopwatch sw4 = new Stopwatch();
sw4.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_String();
sw4.Stop();
Console.WriteLine($"String: {sw4.ElapsedMilliseconds} ms");
// Start of consistency tests:
Console.WriteLine("Running consistency tests...");
bool isConsistent = true;
// Consistency test on random set:
for (int i = 0; i < samples.Length; ++i)
{
int s = samples[i];
int a = s.Digits_IfChain();
int b = s.Digits_Log10();
int c = s.Digits_While();
int d = s.Digits_String();
if (a != b || c != d || a != c)
{
Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
isConsistent = false;
break;
}
}
// Consistency test of special values:
samples = new int[]
{
0,
int.MinValue, -1000000000, -999999999, -100000000, -99999999, -10000000, -9999999, -1000000, -999999, -100000, -99999, -10000, -9999, -1000, -999, -100, -99, -10, -9, - 1,
int.MaxValue, 1000000000, 999999999, 100000000, 99999999, 10000000, 9999999, 1000000, 999999, 100000, 99999, 10000, 9999, 1000, 999, 100, 99, 10, 9, 1,
};
for (int i = 0; i < samples.Length; ++i)
{
int s = samples[i];
int a = s.Digits_IfChain();
int b = s.Digits_Log10();
int c = s.Digits_While();
int d = s.Digits_String();
if (a != b || c != d || a != c)
{
Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
isConsistent = false;
break;
}
}
// Consistency test result:
if (isConsistent)
Console.WriteLine("Consistency tests are OK");
}
// Int64 Performance Tests:
private static void RunTests_Int64()
{
Console.WriteLine("\r\nInt64");
const int size = 100000000;
long[] samples = new long[size];
Random random = new Random((int)DateTime.Now.Ticks);
for (int i = 0; i < size; ++i)
samples[i] = Math.Sign(random.Next(-1, 1)) * (long)(random.NextDouble() * long.MaxValue);
Stopwatch sw1 = new Stopwatch();
sw1.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_IfChain();
sw1.Stop();
Console.WriteLine($"IfChain: {sw1.ElapsedMilliseconds} ms");
Stopwatch sw2 = new Stopwatch();
sw2.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_Log10();
sw2.Stop();
Console.WriteLine($"Log10: {sw2.ElapsedMilliseconds} ms");
Stopwatch sw3 = new Stopwatch();
sw3.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_While();
sw3.Stop();
Console.WriteLine($"While: {sw3.ElapsedMilliseconds} ms");
Stopwatch sw4 = new Stopwatch();
sw4.Start();
for (int i = 0; i < size; ++i) samples[i].Digits_String();
sw4.Stop();
Console.WriteLine($"String: {sw4.ElapsedMilliseconds} ms");
// Start of consistency tests:
Console.WriteLine("Running consistency tests...");
bool isConsistent = true;
// Consistency test on random set:
for (int i = 0; i < samples.Length; ++i)
{
long s = samples[i];
int a = s.Digits_IfChain();
int b = s.Digits_Log10();
int c = s.Digits_While();
int d = s.Digits_String();
if (a != b || c != d || a != c)
{
Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
isConsistent = false;
break;
}
}
// Consistency test of special values:
samples = new long[]
{
0,
long.MinValue, -1000000000000000000, -999999999999999999, -100000000000000000, -99999999999999999, -10000000000000000, -9999999999999999, -1000000000000000, -999999999999999, -100000000000000, -99999999999999, -10000000000000, -9999999999999, -1000000000000, -999999999999, -100000000000, -99999999999, -10000000000, -9999999999, -1000000000, -999999999, -100000000, -99999999, -10000000, -9999999, -1000000, -999999, -100000, -99999, -10000, -9999, -1000, -999, -100, -99, -10, -9, - 1,
long.MaxValue, 1000000000000000000, 999999999999999999, 100000000000000000, 99999999999999999, 10000000000000000, 9999999999999999, 1000000000000000, 999999999999999, 100000000000000, 99999999999999, 10000000000000, 9999999999999, 1000000000000, 999999999999, 100000000000, 99999999999, 10000000000, 9999999999, 1000000000, 999999999, 100000000, 99999999, 10000000, 9999999, 1000000, 999999, 100000, 99999, 10000, 9999, 1000, 999, 100, 99, 10, 9, 1,
};
for (int i = 0; i < samples.Length; ++i)
{
long s = samples[i];
int a = s.Digits_IfChain();
int b = s.Digits_Log10();
int c = s.Digits_While();
int d = s.Digits_String();
if (a != b || c != d || a != c)
{
Console.WriteLine($"Digits({s}): IfChain={a} Log10={b} While={c} String={d}");
isConsistent = false;
break;
}
}
// Consistency test result:
if (isConsistent)
Console.WriteLine("Consistency tests are OK");
}
}
}

- 3,332
- 15
- 36
- 40
-
6I like this solution, it's much more readable than maths tricks and the speed speaks for itself, kudos. – MrLore Jul 17 '18 at 11:55
-
6Why is this not marked as the solution? Performance matters and this seems to be the most extensive answer. – Martien de Jong Dec 06 '18 at 18:50
-
Interesting, I get [different results](https://dotnetfiddle.net/fqEbWc). For random values Log10 and brute force are almost the same but for `long.MaxValue` Log10 is significantly better. Or is it just in .NET Core? – György Kőszeg Nov 21 '19 at 18:23
-
@GyörgyKőszeg: I've added tests for Int64. Please be aware that the tests for `Int32` and `Int64` generate different datasets, which may explain why `Int64` got faster than `Int32` in some cases. Although, within the `Int32` test and within the `Int64` test the datasets are not changed when testing the different calculation methods. Now regarding .NET Core, I doubt there is any magic optimization in the Math library which would change these results, but I would love to hear more about that (my answer is already huge, probably one of the biggest in S.O. ;-) – sɐunıɔןɐqɐp Nov 22 '19 at 15:19
-
@GyörgyKőszeg: Also, low-level performance measuments are very tricky. I usually prefer to keep the code as simple as possible (I prefer simple `for` loops over `enumerations`, I pre-process random datasets, and avoid the use of generics, Tasks, `Function<>`, `Action<>`, or any black-boxed measurement framework). In summary, keep it simple. I also kill all unnecessary applications (Skype, Windows Defender, disable Anti-Virus, Chrome, Microsoft Office cache, etc). – sɐunıɔןɐqɐp Nov 22 '19 at 15:32
-
I also see you changed the method for adding `1` when the number is negative: allocating the temporary `sign` variable and adding it before returning from the function may be causing a measurement difference due to differences in the resulting IL code. – sɐunıɔןɐqɐp Nov 22 '19 at 15:33
-
In the meantime I checked it and yes, `Log10` is much better in .NET Core (maybe it also can use intrinsic solutions if supported by the hardware). For `long.MaxValue`, in .NET Framework 4.7.2 `Log10` is slower by 28% whereas in .NET Core the chained ifs are slower by 80% (in both cases I considered the negative sign). Btw, that `PerformanceTest` class is written by me and I replaced all of my formerly verbose benchmarks to use that. :) The only overhead is the cost of a virtual method call (unless for parameterized tests). – György Kőszeg Nov 22 '19 at 16:27
-
@GyörgyKőszeg: Thanks a lot for your feedback, I've expanded the range of the performance tests to cover .NET Core as well. Indeed .NET Core provides a different result for 64-bit numbers (a.k.a. `long` or `Int64`). – sɐunıɔןɐqɐp Nov 22 '19 at 19:40
-
If you pass `int.MinValue`, the Log10 one crashes with "Negating the minimum value of a twos complement number is invalid.".`Math.Abs(int.MinValue)` can't return 2147483648 as an int. – Alan Singfield Dec 06 '19 at 08:47
-
@AlanSingfield: Thanks for the update, and indeed you are right. I've written consistency tests to cover all border cases, and updated my answer. Now I could also explain the peformance difference between .NET Core and .NET Framework. And different Platform settings (`x86` / `x64`) produce different results. – sɐunıɔןɐqɐp Dec 06 '19 at 15:17
-
Thanks for the feedback, I've posted a binary search version for the int32 and am working on a rainbow table version which is looking to be even faster. Nothing like a good bit of code golf! – Alan Singfield Dec 06 '19 at 23:24
Not directly C#, but the formula is: n = floor(log10(x)+1)

- 7,723
- 7
- 59
- 122
-
4
-
2@Klaus - log10(0) is actually undefined. But, you are correct in that it is a special case that need to be tested for and treated separately. This is also true for any non positive integer number. See comments to Steve's answer. – ysap Jun 03 '14 at 11:50
-
@ysap: Log10 is quite tricky to get working correctly. Do you have any idea on how to implement it correctly for all range of possible input values? – sɐunıɔןɐqɐp Dec 06 '19 at 15:59
-
@sɐunıɔןɐqɐp - `log10` is in most cases a library function. Why would you want to implement it yourself, and what issues do you encounter? `log10(x) = log2(x) / log2(10)`, or generally `logA(x) = logB(x) / logB(A)`. – ysap Dec 08 '19 at 17:42
-
I didn't mean to implement Log10 again, I mean `Log10(0)` is -infinity. Log10 cannot be used to calculate num of digits of negative numbers unless you use `Math.Abs()` before passing the value to Log10. But then `Math.Abs(int.MinValue)` throws an Exception (`long.MinValue` too, in case of Int64). If we cast the number to double before passing it to Log10, then it works for almost all numbers except for `-999999999999999999` (in case of Int64). Do you know any formula for calculating the num of digits which uses log10 and accepts any int32 or int64 value as input and outputs only valid values? – sɐunıɔןɐqɐp Dec 09 '19 at 09:15
-
@sɐunıɔןɐqɐp - yes, `log10()` has limitations, and one needs to know what he's doing. It discussed above. – ysap Dec 10 '19 at 18:35
Answers already here work for unsigned integers, but I have not found good solutions for getting number of digits from decimals and doubles.
public static int Length(double number)
{
number = Math.Abs(number);
int length = 1;
while ((number /= 10) >= 1)
length++;
return length;
}
//number of digits in 0 = 1,
//number of digits in 22.1 = 2,
//number of digits in -23 = 2
You may change input type from double
to decimal
if precision matters, but decimal has a limit too.

- 70,104
- 56
- 326
- 368
The answer of Steve is correct, but it doesn't work for integers less than 1.
Here an updated version that does work for negatives:
int digits = n == 0 ? 1 : Math.Floor(Math.Log10(Math.Abs(n)) + 1)

- 1
- 1

- 153,850
- 22
- 249
- 325
-
You are missing a castingto int: `digits = n == 0 ? 1 : (int)Math.Floor(Math.Log10(Math.Abs(n)) + 1);` – sɐunıɔןɐqɐp Jun 29 '18 at 09:02
-
I did it without if statement: digits = (int)Math.Floor(Math.Abs(Math.Log10(Math.Abs(n))) + 1) – KOLRH Aug 02 '18 at 09:48
-
Using recursion (sometimes asked on interviews)
public int CountDigits(int number)
{
// In case of negative numbers
number = Math.Abs(number);
if (number >= 10)
return CountDigits(number / 10) + 1;
return 1;
}
static void Main(string[] args)
{
long blah = 20948230498204;
Console.WriteLine(blah.ToString().Length);
}
Here's an implementation using a binary search. Looks to be the fastest so far on int32.
Int64 implementation is left as an exercise for the reader(!)
I tried using Array.BinarySearch rather than hard-coding the tree, but that was about half the speed.
EDIT: A lookup table is much faster than the binary search, at the expense of using more memory. Realistically I'd probably use the binary search one in production, the lookup table is a lot of complexity for a speed gain that's likely to be overshadowed by other parts of the software.
Lookup-Table: 439 ms
Binary-Search: 1069 ms
If-Chain: 1409 ms
Log10: 1145 ms
While: 1768 ms
String: 5153 ms
Lookup table version:
static byte[] _0000llll = new byte[0x10000];
static byte[] _FFFFllll = new byte[0x10001];
static sbyte[] _hhhhXXXXdigits = new sbyte[0x10000];
// Special cases where the high DWORD is not enough information to find out how
// many digits.
static ushort[] _lowordSplits = new ushort[12];
static sbyte[] _lowordSplitDigitsLT = new sbyte[12];
static sbyte[] _lowordSplitDigitsGE = new sbyte[12];
static Int32Extensions()
{
// Simple lookup tables for number of digits where value is
// 0000xxxx (0 .. 65535)
// or FFFFxxxx (-1 .. -65536)
precomputePositiveLo16();
precomputeNegativeLo16();
// Hiword is a little more complex
precomputeHiwordDigits();
}
private static void precomputeHiwordDigits()
{
int b = 0;
for(int hhhh = 0; hhhh <= 0xFFFF; hhhh++)
{
// For hiword hhhh, calculate integer value for loword of 0000 and FFFF.
int hhhh0000 = (unchecked(hhhh * 0x10000)); // wrap around on negatives
int hhhhFFFF = hhhh0000 + 0xFFFF;
// How many decimal digits for each?
int digits0000 = hhhh0000.Digits_IfChain();
int digitsFFFF = hhhhFFFF.Digits_IfChain();
// If same number of decimal digits, we know that when we see that hiword
// we don't have to look at the loword to know the right answer.
if(digits0000 == digitsFFFF)
{
_hhhhXXXXdigits[hhhh] = (sbyte)digits0000;
}
else
{
bool negative = hhhh >= 0x8000;
// Calculate 10, 100, 1000, 10000 etc
int tenToThePower = (int)Math.Pow(10, (negative ? digits0000 : digitsFFFF) - 1);
// Calculate the loword of the 10^n value.
ushort lowordSplit = unchecked((ushort)tenToThePower);
if(negative)
lowordSplit = unchecked((ushort)(2 + (ushort)~lowordSplit));
// Store the split point and digits into these arrays
_lowordSplits[b] = lowordSplit;
_lowordSplitDigitsLT[b] = (sbyte)digits0000;
_lowordSplitDigitsGE[b] = (sbyte)digitsFFFF;
// Store the minus of the array index into the digits lookup. We look for
// minus values and use these to trigger using the split points logic.
_hhhhXXXXdigits[hhhh] = (sbyte)(-b);
b++;
}
}
}
private static void precomputePositiveLo16()
{
for(int i = 0; i <= 9; i++)
_0000llll[i] = 1;
for(int i = 10; i <= 99; i++)
_0000llll[i] = 2;
for(int i = 100; i <= 999; i++)
_0000llll[i] = 3;
for(int i = 1000; i <= 9999; i++)
_0000llll[i] = 4;
for(int i = 10000; i <= 65535; i++)
_0000llll[i] = 5;
}
private static void precomputeNegativeLo16()
{
for(int i = 0; i <= 9; i++)
_FFFFllll[65536 - i] = 1;
for(int i = 10; i <= 99; i++)
_FFFFllll[65536 - i] = 2;
for(int i = 100; i <= 999; i++)
_FFFFllll[65536 - i] = 3;
for(int i = 1000; i <= 9999; i++)
_FFFFllll[65536 - i] = 4;
for(int i = 10000; i <= 65535; i++)
_FFFFllll[65536 - i] = 5;
}
public static int Digits_LookupTable(this int n)
{
// Split input into low word and high word.
ushort l = unchecked((ushort)n);
ushort h = unchecked((ushort)(n >> 16));
// If the hiword is 0000 or FFFF we have precomputed tables for these.
if(h == 0x0000)
{
return _0000llll[l];
}
else if(h == 0xFFFF)
{
return _FFFFllll[l];
}
// In most cases the hiword will tell us the number of decimal digits.
sbyte digits = _hhhhXXXXdigits[h];
// We put a positive number in this lookup table when
// hhhh0000 .. hhhhFFFF all have the same number of decimal digits.
if(digits > 0)
return digits;
// Where the answer is different for hhhh0000 to hhhhFFFF, we need to
// look up in a separate array to tell us at what loword the change occurs.
var splitIndex = (sbyte)(-digits);
ushort lowordSplit = _lowordSplits[splitIndex];
// Pick the correct answer from the relevant array, depending whether
// our loword is lower than the split point or greater/equal. Note that for
// negative numbers, the loword is LOWER for MORE decimal digits.
if(l < lowordSplit)
return _lowordSplitDigitsLT[splitIndex];
else
return _lowordSplitDigitsGE[splitIndex];
}
Binary search version
public static int Digits_BinarySearch(this int n)
{
if(n >= 0)
{
if(n <= 9999) // 0 .. 9999
{
if(n <= 99) // 0 .. 99
{
return (n <= 9) ? 1 : 2;
}
else // 100 .. 9999
{
return (n <= 999) ? 3 : 4;
}
}
else // 10000 .. int.MaxValue
{
if(n <= 9_999_999) // 10000 .. 9,999,999
{
if(n <= 99_999)
return 5;
else if(n <= 999_999)
return 6;
else
return 7;
}
else // 10,000,000 .. int.MaxValue
{
if(n <= 99_999_999)
return 8;
else if(n <= 999_999_999)
return 9;
else
return 10;
}
}
}
else
{
if(n >= -9999) // -9999 .. -1
{
if(n >= -99) // -99 .. -1
{
return (n >= -9) ? 1 : 2;
}
else // -9999 .. -100
{
return (n >= -999) ? 3 : 4;
}
}
else // int.MinValue .. -10000
{
if(n >= -9_999_999) // -9,999,999 .. -10000
{
if(n >= -99_999)
return 5;
else if(n >= -999_999)
return 6;
else
return 7;
}
else // int.MinValue .. -10,000,000
{
if(n >= -99_999_999)
return 8;
else if(n >= -999_999_999)
return 9;
else
return 10;
}
}
}
}
Stopwatch sw0 = new Stopwatch();
sw0.Start();
for(int i = 0; i < size; ++i) samples[i].Digits_BinarySearch();
sw0.Stop();
Console.WriteLine($"Binary-Search: {sw0.ElapsedMilliseconds} ms");

- 136
- 4
-
Very interesting approach. It's indeed faster than "Log10", "string.Length", and "While" methods for uniformly distributed integer values. In real case scenarios, the distribution of the integer values must always be considered on if-chain-like solutions. +1 – sɐunıɔןɐqɐp Dec 07 '19 at 11:17
-
The LookUpTable approach seems to be super fast for scenarios where memory access is not the bottleneck. I strongly believe that for scenarios with frequent memory access, the LookUpTable gets slower than if-chain-like methods, like the BinSearch one you've suggested. By the way, do you have the `Int64` implementation for the LookUpTable? Or do you think it is too complicated to implement it? I'd like to run the performance tests later on the complete set. – sɐunıɔןɐqɐp Dec 09 '19 at 09:37
-
Hey, didn't get as far as the 64-bit one. The principle would have to be slightly different in that you'd need 4x levels rather than just hiword and loword. Definitely agree that in the real world, your CPU cache will have lots of other competing needs for the space, and there's a lot of room for improvement in cutting down the size of the lookup (>>1 then even numbers only comes to mind). The binary search one could be improved by biasing towards 9,10,8 digits instead of 1,2,3,4 - given the distribution of your random data set. – Alan Singfield Dec 09 '19 at 10:50
-
Note that any branch based implementation is going to be hard to measure due to how the CPU branch predictor behaves on any data set. You could probably construct a worst case data set by forcing the data to alternate the branches taken. – Jeremy Lakeman Mar 24 '22 at 05:10
dividing a number by 10 will give you the left most digit then doing a mod 10 on the number gives the number without the first digit and repeat that till you have all the digits

- 423
- 1
- 5
- 16
int i = 855865264;
int NumLen = i.ToString().Length;

- 239,200
- 50
- 490
- 574

- 15,024
- 26
- 81
- 118
-
3fails for negative int, and for numbers like 23.00. Do a `string.TrimStart('-')` better – nawfal Dec 14 '12 at 10:19
Total digits of integer:
double input = Convert.ToDouble(Console.ReadLine());
double b = Math.Floor(Math.Log10(input) + 1);
int c = Convert.ToInt32(b);

- 21
- 2
Not able to comment, but this is in relation to sɐunıɔןɐqɐp's excellent comment.
This function works with doubles.
I also believe there was an error with the negative comparisons.
/// <summary>
/// counts the digits of the integral part of a number. <br></br>
/// 4 -> 1; 4.3 -> 1; -4 -> 1; -0.4 -> 0, 1e53 -> 53
/// </summary>
/// <param name="n"></param>
/// <returns>number 1+</returns>
public static int IntegralDigitLength( double n )
{
//this if-chain is allegedly the best way
//https://stackoverflow.com/questions/4483886/how-can-i-get-a-count-of-the-total-number-of-digits-in-a-number
if(n< 1 && n > -1 )
{
return 0;
}
if( n >= 0 )
{
if( n < 10L ) return 1;
if( n < 100L ) return 2;
if( n < 1000L ) return 3;
if( n < 10000L ) return 4;
if( n < 100000L ) return 5;
if( n < 1000000L ) return 6;
if( n < 10000000L ) return 7;
if( n < 100000000L ) return 8;
if( n < 1000000000L ) return 9;
if( n < 10000000000L ) return 10;
if( n < 100000000000L ) return 11;
if( n < 1000000000000L ) return 12;
if( n < 10000000000000L ) return 13;
if( n < 100000000000000L ) return 14;
if( n < 1000000000000000L ) return 15;
if( n < 10000000000000000L ) return 16;
if( n < 100000000000000000L ) return 17;
if( n < 1000000000000000000L ) return 18;
n = Math.Floor( n );
var numOfDigits = 19;
while( true )
{
double comparison = Math.Pow( 10, numOfDigits );
if( n <= comparison )
{
return numOfDigits;
}
numOfDigits++;
}
}
else
{
if( n > -10L ) return 1;
if( n > -100L ) return 2;
if( n > -1000L ) return 3;
if( n > -10000L ) return 4;
if( n > -100000L ) return 5;
if( n > -1000000L ) return 6;
if( n > -10000000L ) return 7;
if( n > -100000000L ) return 8;
if( n > -1000000000L ) return 9;
if( n > -10000000000L ) return 10;
if( n > -100000000000L ) return 11;
if( n > -1000000000000L ) return 12;
if( n > -10000000000000L ) return 13;
if( n > -100000000000000L ) return 14;
if( n > -1000000000000000L ) return 15;
if( n > -10000000000000000L ) return 16;
if( n > -100000000000000000L ) return 17;
if( n > -1000000000000000000L ) return 18;
n = Math.Floor( n );
var numOfDigits = 19;
while( true )
{
if( n <= Math.Pow( -10, numOfDigits ) )
{
return numOfDigits;
}
numOfDigits++;
}
}
}
It passes the following unit tests:
[Test]
public void IntegralDigitLength()
{
Assert.AreEqual( 1, Logic.IntegralDigitLength( 1 ) );
Assert.AreEqual( 1, Logic.IntegralDigitLength( 2 ) );
Assert.AreEqual( 1, Logic.IntegralDigitLength( -3 ) );
Assert.AreEqual( 1, Logic.IntegralDigitLength( -3.4 ) );
Assert.AreEqual( 1, Logic.IntegralDigitLength( 3.4 ) );
Assert.AreEqual( 1, Logic.IntegralDigitLength( 9.9 ) );
Assert.AreEqual( 2, Logic.IntegralDigitLength( 10 ) );
Assert.AreEqual( 2, Logic.IntegralDigitLength( 19 ) );
Assert.AreEqual( 2, Logic.IntegralDigitLength( 19.9 ) );
Assert.AreEqual( 2, Logic.IntegralDigitLength( -19.9 ) );
Assert.AreEqual( 5, Logic.IntegralDigitLength( 12345 ) );
Assert.AreEqual( 5, Logic.IntegralDigitLength( 92345 ) );
Assert.AreEqual( 4, Logic.IntegralDigitLength( 02345 ) );
Assert.AreEqual( 1, Logic.IntegralDigitLength( 00005 ) );
Assert.AreEqual( 8, Logic.IntegralDigitLength( 47616294 ) );
Assert.AreEqual( 8, Logic.IntegralDigitLength( -47616294 ) );
Assert.AreEqual( 25, Logic.IntegralDigitLength( 1111111111111111111111111f ) );
Assert.AreEqual( 25, Logic.IntegralDigitLength( 4444444444444444444444444f ) );
Assert.AreEqual( 25, Logic.IntegralDigitLength( 9999999999999999999999999f ) );
Assert.AreEqual( 25, Logic.IntegralDigitLength( 1e25 ) );
Assert.AreEqual( 305, Logic.IntegralDigitLength( 1e305 ) );
Assert.AreEqual( 0, Logic.IntegralDigitLength( 1e-3 ) );
}
NB: the last one returns zero, I want it to return 0 for values less than one but greater than -1.

- 49
- 4
It depends what exactly you want to do with the digits. You can iterate through the digits starting from the last to the first one like this:
int tmp = number;
int lastDigit = 0;
do
{
lastDigit = tmp / 10;
doSomethingWithDigit(lastDigit);
tmp %= 10;
} while (tmp != 0);

- 3,332
- 15
- 36
- 40

- 10,810
- 14
- 61
- 111
-
1Your logic is reversed. You need to use `%` to get the digit, and then `/=` to cut it down. – julealgon Dec 12 '19 at 21:59
Create a method that returns all digits, and another that counts them:
public static int GetNumberOfDigits(this long value)
{
return value.GetDigits().Count();
}
public static IEnumerable<int> GetDigits(this long value)
{
do
{
yield return (int)(value % 10);
value /= 10;
} while (value != 0);
}
This felt like the more intuitive approach to me when tackling this problem. I tried the Log10
method first due to its apparent simplicity, but it has an insane amount of corner cases and precision problems.
I also found the if
-chain proposed in the other answer to a bit ugly to look at.
I know this is not the most efficient method, but it gives you the other extension to return the digits as well for other uses (you can just mark it private
if you don't need to use it outside the class).
Keep in mind that it does not consider the negative sign as a digit.

- 7,072
- 3
- 32
- 77
convert into string and then you can count tatal no of digit by .length method. Like:
String numberString = "855865264".toString();
int NumLen = numberString .Length;
Assuming your question was referring to an int, the following works for negative/positive and zero as well:
Math.Floor((decimal) Math.Abs(n)).ToString().Length

- 1,031
- 13
- 20