I am not a math genius, as any math genius who reviews my work is happy to tell me. Even so, when programming I’m often faced with math challenges where a math education would benefit. My most recent puzzle is how to count the number of digits in a value without first converting the value into a string.
If you visit this blog regularly, yes, this Lesson hints at an upcoming Exercise challenge. Still, the problem intrigued me: Does some mathematical trick exist that determines how a value such as 12345 contains five digits? Rather than research such a solution, I just started to code. Typical.
Given the Power of the Computer, I devised a brute-force method to determine the number of digits in a value by subtracting successive powers of 10 from a given number. To ensure that large values are properly processed, I use long integer types in the following code:
2022_08_20-Lesson-a.c
#include <stdio.h>
int main()
{
long d;
int x,l;
long value[10] = {
1, 12, 123, 1234, 12345,
123456, 1234567, 12345678,
123456789, 1234567890
};
for( x=0; x<10; x++ )
{
l=d=1;
while( d<=10000000000 )
{
if( value[x]<d )
{
printf("%ld is %d digits long\n",value[x],l-1);
break;
}
d*=10;
l++;
}
}
return(0);
}
The value[] array holds ten numbers progressing from 1 through 1234567890. A for loop churns through each of the values.
Within the for loop, a while loop compares value[x] with successive powers of 10. The looping value d starts at one, and multiplies itself by 10 each iteration until its value equals 10,000,000,000.
Within the while loop, an if statement compares the value submitted, value[x], with d, the power of 10. When the value is less, then digit counter variable l (little L) determines the number of digits. Here is the output:
1 is 1 digits long
12 is 2 digits long
123 is 3 digits long
1234 is 4 digits long
12345 is 5 digits long
123456 is 6 digits long
1234567 is 7 digits long
12345678 is 8 digits long
123456789 is 9 digits long
1234567890 is 10 digits long
This test works fine, but what I truly adore is generating random numbers to try the code. The problem here is that random values are typically and uniformly huge, so they must be pared down to a smaller length. Such an exercise requires more math magic, at which I confess to being a poor conjurer. Still, I took a stab at it in this update to the code:
2022_08_20-Lesson-b.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
int main()
{
long d;
int l,r;
long value;
/* seed the randomizer */
srand( (unsigned)time(NULL) );
/* obtain the random value */
value = rand();
/* obtain a random value length */
r = rand() % 11;
/* truncate the value */
value %= (int)pow(10,r);
/*
now count the digits, which will end
up being the same value as 'r', but
what-the-hey
*/
l=d=1;
while( d<=10000000000 )
{
if( value<d )
{
printf("%ld is %d digits long\n",value,l-1);
break;
}
d*=10;
l++;
}
return(0);
}
Two random values are required to generate a random number of a random length. The first is the value itself, value in the above code. The second is the truncating value, r above.
At Line 22, value is truncated by taking r to the power of 10, typecasting it as an integer, and using the mod assignment operator, %=. This expression reduces the random value down to a digit range equal to the value of r — which is what the remainder of the code attempts to discover. Still, the point is to try the technique on a random value, and it works:
36398 is 5 digits long
9070012 is 7 digits long
99086819 is 8 digits long
599137240 is 9 digits long
4 is 1 digits long
I would bet a whole donut that a better way exists to count the digits in a number. If not a better way, perhaps even a different way that makes more sense. If you know of one, please let me know. I’m not desperate, just curious.
I think you should be able to do something with logarithms (base 10).
Why did you think it necessary to specify “whole” donut? I don’t think anyone would assume you meant a half eaten one 🙂
Yep, there’s that maths thing: I would never assume logarithms because it was two week of school and then we moved on. I looked for a book on logarithms a while back. Nada. The only one I found was tepid.
Donuts are precious.
This is a selection of numbers with their base 10 logarithms:
1 – 0
2 – 0.301030
9 – 0.954243
10 – 1
99 – 1.995635
100 – 2
999 – 2.999565
1000 – 3
9999 – 3.999957
10000 – 4
99999 – 4.999996
100000 – 5
999999 – 5.999999
so all you need to do is round the logarithm down to the nearest integer and add 1, eg
digits = floor(log10(n)) + 1;
I’m not professional programmer, but this type of problems, counting digits in a number, i’ve always done it this way:
long number;
int digits = 0;
while (number)
{
digits++;
number /= 10;
}
@ivanko I like your approach! That’s math I can understand. 😀