I would like to use the first five digits of a number for computation.
In general, floating point numbers are encoded using binary and OP wants to use 5 significant decimal digits. This is problematic as numbers like 4.23654897E-05
and 4.2365E-05
are not exactly representable as a float/double
. The best we can do is get close.
The floor*()
approach has problems with 1) negative numbers (should have used trunc()
) and 2) values near x.99995
that during rounding may change the number of digits. I strongly recommend against it here as such solutions employing it fail many corner cases.
The *10000 * power10
, round, /(10000 * power10)
approach suffers from 1) power10
calculation (1e5 in this case) 2) rounding errors in the multiple, 3) overflow potential. The needed power10
may not be exact. *
errors show up with cases when the product is close to xxxxx.5
. Often this intermediate calculation is done using wider double
math and so the corner cases are rare. Bad rounding using (some_int_type)
which has limited range and is a truncation instead of the better round()
or rint()
.
An approach that gets close to OP's goal: print to 5 significant digits using %e
and convert back. Not highly efficient, yet handles all cases well.
int main(void) {
float num = 4.23654897E-05f;
// sign d . dddd e sign expo + \0
#define N (1 + 1 + 1 + 4 + 1 + 1 + 4 + 1)
char buf[N*2]; // Use a generous buffer - I like 2x what I think is needed.
// OP wants 5 significant digits so print 4 digits after the decimal point.
sprintf(buf, "%.4e", num);
float rounded = (float) atof(buf);
printf("%.5e %s\n", rounded, buf);
}
Output
4.23650e-05 4.2365e-05
Why 5 in %.5e
: Typical float
will print up to 6 significant decimal digits as expected (research FLT_DIG
), so 5 digits after the decimal point are printed. The exact value of rounded
in this case was about 4.236500171...e-05
as 4.2365e-05 is not exactly representable as a float
.