I am working on an embedded application and need to print floating point values. Due to space and other limitations I can only use putchar() for output.
I am trying
I think my main approach would be to separate the integer portion of the float's value from the decimal portion.
If you can use some sort of rounding or conversion to integer function, you can use the putLong method you already have to output the integer portion.
Output a decimal point.
Then, subtract that int from the float to isolate the decimal. Now, for the decimal, you can either try to determine the number of places after the decimal, or just multiply by an arbitrarily large power of 10, then strip off extraneous zeroes from the right-hand side of the resulting int and again apply putLong for the result.
I suspect there may be a more efficient or simpler way to do this, but I'm pretty sure this approach will work. Looking up the way a float's bits are used to represent the exponent and value components may also be useful.
What range of values and accuracy/precision requirements do you need? Printing the exact value of a floating point number in decimal is a very hard problem and requires up to 8 kb or so (I could be off by a few powers of 2; this is off the top of my head) of working space if you support 80-bit or 128-bit long double
values. You can probably get by with 1 kb or so if you only support double
, and essentially no working space if you just want to print poor approximations.
OK, so here's a really basic version:
void putDouble(double x, int p)
{
long d;
if (x<0) {
putchar('-');
x=-x;
}
d = x;
putLong(d);
putchar('.');
while (p--) {
x = (x - d) * 10;
d = x;
putchar('0'+d);
}
}
You might want to fix your putLong
to handle numbers longer than 2 digits, 2. :-)
Here's a possible solution:
typedef enum
{
DEC1 = 10,
DEC2 = 100,
DEC3 = 1000,
DEC4 = 10000,
DEC5 = 100000,
DEC6 = 1000000,
} tPrecision ;
void putFloat( float f, tPrecision p )
{
long i = (long)f ;
putLong( i ) ;
f = (f - i) * p ;
i = abs((long)f) ;
if( fabs(f) - i >= 0.5f )
{
i++ ;
}
putchar('.') ;
putLong( i ) ;
putchar('\n') ;
}
You would use it thus:
putFloat( 3.14159f, DEC3 ) ;
which will output "3.142", note the rounding up of the third digit.
If you only need a fixed number of decimal places, you can do away with the precision argument and hard-code it.
When using this function you should be aware that a float only has 6 significant digits of precision, not six decimal places. So if you attempt to print say 123.456 using DEC6 you will get erroneous digits after the third place. Any digits after the 6th significant digit should be ignored, but writing the code to take account of that may be unnecessary in your application or more expensive that you would wish given your constraints.