How to calculate the length of number before decimal and after (?)
Careful what you wish for ....
9.456 is not exactly presentable as a double. It is not of the form some_integer*2some_power.
double a = 9.456;
Instead a nearby representative value is used1. Its exact decimal value is perhaps not that useful for this task:
9.455999999999999516830939683131873607635498046875
//123456789012345678901234567890123456789012345678
In this case the integer digit count is 1 and the fraction count 48.
Instead, a more practical question/answer is: "How to calculate the length of number before decimal point and after of a rounded output?"
This is easier. Print the double using "% .*e" to a string to do the heavy lifting, then parse the output.
The precision selected affects the output: see 99.999 below.
Since we are using the rounded decimal output, avoid trying to code this without using sprintf(). Otherwise the corner cases are many.
Sample:
#include <math.h>
#include <stdio.h>
// - d . xxxxxxxxxxx e - eeee \0 spare
#define FMT_N(prec) (1 + 1 + 1 + ((prec) - 1) + 1 + 1 + 4 + 1 + 5)
#define FMT_E(prec) (1 + 1 + 1 + ((prec) - 1) + 1)
#define FMT_Z(prec) (1 + 1 + 1 + ((prec) - 1) - 1)
void get_int_fraction_count(double a, int precision, int *integer, int *fraction) {
*integer = *fraction = 0;
if (!isfinite(a) || a == 0.0) {
return;
}
char buf[FMT_N(precision)];
snprintf(buf, sizeof buf, "% .*e", precision - 1, a);
int expo = atoi(&buf[FMT_E(precision)]);
int digit_count = precision;
for (char *z = &buf[FMT_Z(precision)]; *z == '0'; z--) {
digit_count--;
}
// printf("expo:%d digit_count:%d\n", expo, digit_count);
if (expo >= 0) {
*integer = expo + 1;
if (digit_count > *integer) {
*fraction = digit_count - *integer;
}
} else {
*fraction = digit_count - expo - 1;
}
}
Test: Recommend to use DBL_DIG digits.
void get_int_fraction_count_test(double a, int precision) {
int integer;
int fraction;
get_int_fraction_count(a, precision, &integer, &fraction);
printf("a:% .*e i:%d f:%d\n", precision - 1, a, integer, fraction);
}
int main(void) {
double a = 9.456;
get_int_fraction_count_test(a, 4);
get_int_fraction_count_test(a, DBL_DIG);
get_int_fraction_count_test(0.123, 4);
get_int_fraction_count_test(0.0123, 4);
get_int_fraction_count_test(DBL_MAX, 4);
get_int_fraction_count_test(DBL_TRUE_MIN, 4);
get_int_fraction_count_test(99.999, 4);
get_int_fraction_count_test(99.999, 5);
}
Output
a: 9.456e+00 i:1 f:3
a: 9.45600000000000e+00 i:1 f:3
a: 1.230e-01 i:0 f:3
a: 1.230e-02 i:0 f:4
a: 1.798e+308 i:309 f:0
a: 4.941e-324 i:0 f:327
a: 1.000e+02 i:3 f:0
a: 9.9999e+01 i:2 f:3
1 5,323,254,759,551,926 * 2-49