double/long double printing code
Posted: Tue Jul 07, 2009 10:57 pm
hey, as one of the functions of this forum is to have code testing, I'd like to present some code that I think works great, but could use some extra refining and case handling. This code prints a double-precision floating-point number using some fairly standard functions. This code is easily modifiable to print extended-precision numbers (long double) just by changing every reference of "double" to "long double". This code has been tested in my 32-bit x86 port and 64-bit x86-64 port of my test OS called ArcticOS. The only real kernel-level handling required is the FPU to be initialised with a control word, FINIT to be executed (read the wiki entry), and some sort of FPU-state saving (in multi-tasking kernels). 99% of this is guess-work and I'm sure could be done more efficiently, that's where you guys come in .
This will print up to "precision" digits, less if there are no more digits to print (if the double value is equal to its integer counterpart). I haven't added testing for +/- infinities. Also, the NaN testing is extremely primitive. This code also works when using SSE during compile-time. I release this under the public domain or whatever your country considers to be completely free for any purpose.
Code: Select all
// floating-point printf() support. Usage: %xf/g. Example: %4f (prints a double float to 4 (max) decimal places)
#define MAX_PRECISION 50
#define IsNaN(n) (n != n)
// %f: double/single precision support (double or promoted float, 64-bits)
#if defined(X86_COMMON)
static void print_double_float(double val, size_t precision)
{
size_t cur_prec = 1;
// if the user-defined precision is out-of-bounds, normalize it
if(precision > MAX_PRECISION)
precision = MAX_PRECISION;
// if it's negative, show it!
if(val < 0)
{
putch('-');
// change to a positive value
val = -val;
}
// check to see if it is Not-a-Number
if(IsNaN(val))
{
putstr("NaN");
return;
}
// print the integer part of the floating point
print_int((int)val);
// if precision == 0, only print the integer part
if(!precision)
return;
// now on to the decimal potion
putch('.');
// remove the integer part
val -= (double)((int)val);
/* on every iteration, make sure there are still decimal places left that are non-zero,
and make sure we're still within the user-defined precision range. */
while(val > (double)((int)val) && cur_prec++ < precision+1)
{
// move the next decimal into the integer portion and print it
val *= 10;
print_int((int)val);
/* if the value is == the floored value (integer portion),
then there are no more decimal places that are non-zero. */
if(val == (double)((int)val))
return;
// subtract the integer portion
val -= (double)((int)val);
}
}
#endif