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. 😀