This forums is for OS project announcements including project openings, new releases, update notices, test requests, and job openings (both paying and volunteer).
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 .
// 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
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.
// print the integer part of the floating point
print_int((int)val);
What about huge values (overflow)
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
I never actually thought about printing floats or double's yet. If I was going to implement it, I would probably be doing something similar (multiplying by 10 to transform a floating point number into a normal integral number). I used something similar before to generate random floating point numbers.
When the chance of succeeding is 99%, there is still a 50% chance of that success happening.
01000101 wrote:I haven't added testing for +/- infinities. Also, the NaN testing is extremely primitive.
A C99-compliant implementation of a standard lib should provide the functions isnan() and isinf() in <math.h>. I know that's of little help when you're in kernel space, I just wanted to mention it.
I release this under the public domain...
Excellent. Saved for later review when the time comes to add float / double printing to PDCLib.
Every good solution is obvious once you've found it.
// print the integer part of the floating point
print_int((int)val);
What about huge values (overflow)
excellent observation, I do not handle integers > sizeof(size_t) bits wide. I'll probably just do the opposite of what I do to print the decimal (keep dividing by decrementing large multiples of 10) to print large doubles/long doubles.