string format with %g in C
Question
How do I create a string so that it formats floating point numbers to have no trailing decimal point or digits when it is an integer, but to NOT switch to scientific notation for larger numbers?
When I do:
float myFloat= 15.6f;
float myInt = 5.0f;
float myLarge = 7000000.0f;
sprintf(out, "my float is %g", myFloat);
sprintf(out, "my int is %g", myInt);
sprintf(out, "my large is %g", myLarge);
I get something like:
my float is 15.6 my int is 5 my large is 7e+07f
I want all a single format string that will give 15.6, 5, and 700000.
Edited cause comments don't do formatting:
that's what I thought. but a wrapper is pretty inconvenient though as the format strings are embedded in longer format strings:
sprintf(buf, "%d %g", myInt, myFloat);
how do you wrap that?
sprintf(buf, "%d %g", myInt, Wrapper(myFloat));??
what should Wrapper return? Or worse:
sprintf(buf, "%d %s", myInt, Wrapper(myFloat));??
Solution
I don't think you can get this with %g
, as %g
gives you the shorter of %e
or %f
.
So, I don't think there's a single printf
argument that satisfies you. For 15.6, you could use %2.1f
; for 7000000, you could use %7.0f
.
Your best bet is probably to write a wrapper function that would look at the size of your value and apply the correct printf
argument.
OTHER TIPS
You can format with "%.*f", which allows you to pass the precision as a separate parameter to e.g. sprintf. I've used this in the past when I wanted to display 0, 1, 2, or maybe 3 digits nicely without extra trailing 0's. Write a little helper function which takes the double/float and returns an integer precision (by multiplying by 1000 and then doing modulo 10, 100, 1000). Then call sprintf with "%.*f", call the helper function, and pass the float.
Mike's approach is reasonable, but you can compute the number of digits directly using the log10 function, and use either floor or ceil to verify that you in fact have an integer value. Something like:
#include <math.h>
double x;
...
if (floor(x) == x && x != 0.0) { // x is an non-zero integer value
int digits = floor(log10(fabs(x)+0.5)) + 1;
printf("x is %.*f\n", digits, x);
}
Unpacking that chain of function calls, we first take the absolute value to make sure the argument is non-negative, add 0.5 to the known integer value to take care of any possible roundoff errors in computing log10 of an exact power of 10, combine log10 and floor to get the exponent of the largest power of 10 less than fabs(x)+0.5, and finally add 1 to get the number of digits needed to represent x. Here are some sample values (from OpenOffice, but the C log10 function should calculate in similar precision):
x log10(x+0.5)
1 0.176091259055681000
9 0.977723605288848000
10 1.021189299069940000
99 1.997823080745730000
100 2.002166061756510000
999 2.999782798454140000
1000 3.000217092972230000
10000 4.000021714181250000
100000 5.000002171466980000
1000000 6.000000217147190000
10000000 7.000000021714720000
100000000 8.000000002171470000
1000000000 9.000000000217150000
Replace %g with %.10g to show up to 10 significant figures