Here are a few different C++ implementations* of a function named digits()
which takes a size_t
as argument and returns its number of digits. If your number is negative, you are going to have to pass its absolute value to the function in order for it to work properly:
The While Loop
int digits(size_t i)
{
int count = 1;
while (i /= 10) {
count++;
}
return count;
}
The Exhaustive Optimization Technique
int digits(size_t i) {
if (i > 9999999999999999999ull) return 20;
if (i > 999999999999999999ull) return 19;
if (i > 99999999999999999ull) return 18;
if (i > 9999999999999999ull) return 17;
if (i > 999999999999999ull) return 16;
if (i > 99999999999999ull) return 15;
if (i > 9999999999999ull) return 14;
if (i > 999999999999ull) return 13;
if (i > 99999999999ull) return 12;
if (i > 9999999999ull) return 11;
if (i > 999999999ull) return 10;
if (i > 99999999ull) return 9;
if (i > 9999999ull) return 8;
if (i > 999999ull) return 7;
if (i > 99999ull) return 6;
if (i > 9999ull) return 5;
if (i > 999ull) return 4;
if (i > 99ull) return 3;
if (i > 9ull) return 2;
return 1;
}
The Recursive Way
int digits(size_t i) { return i < 10 ? 1 : 1 + digits(i / 10); }
Using snprintf()
as a Character Counter
⚠ Requires #include <stdio.h>
and may incur a significant performance penalty compared to other solutions. This method capitalizes on the fact that snprintf()
counts the characters it discards when the buffer is full. Therefore, with the right arguments and format specifiers, we can force snprintf()
to give us the number of digits of any size_t
.
int digits(size_t i) { return snprintf (NULL, 0, "%llu", i); }
The Logarithmic Way
⚠ Requires #include <cmath>
and is unreliable for unsigned integers with more than 14 digits.
// WARNING! There is a silent implicit conversion precision loss that happens
// when we pass a large int to log10() which expects a double as argument.
int digits(size_t i) { return !i? 1 : 1 + log10(i); }
Driver Program
You can use this program to test any function that takes a size_t
as argument and returns its number of digits. Just replace the definition of the function digits()
in the following code:
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <chrono>
using std::cout;
using namespace std::chrono;
// REPLACE this function definition with the one you want to test.
int digits(size_t i)
{
int count = 1;
while (i /= 10) {
count++;
}
return count;
}
// driver code
int main ()
{
const int max = digits(~0ull);
size_t i = 0, d;
do {
auto t0 = high_resolution_clock::now();
d = digits(i);
auto t1 = high_resolution_clock::now();
duration<double, std::nano> te = t1 - t0;
cout << i << " has " << d << " digits (" << te.count() << " ns).\n";
i = d < max ? (!i ? 9 : 10 * i - 1) : ~0ull;
t0 = high_resolution_clock::now();
d = digits(i);
t1 = high_resolution_clock::now();
te = t1 - t0;
cout << i << " has " << d << " digits (" << te.count() << " ns).\n";
} while (++i);
}
* Everything was tested on a Windows 10 (64-bit) machine using GCC 12.2.0 in Visual Studio Code.