double/long double printing code

This forums is for OS project announcements including project openings, new releases, update notices, test requests, and job openings (both paying and volunteer).
Post Reply
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

double/long double printing code

Post by 01000101 »

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 :wink: .

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
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.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Re: double/long double printing code

Post by Combuster »

Code: Select all

    // 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 ]
User avatar
Creature
Member
Member
Posts: 548
Joined: Sat Dec 27, 2008 2:34 pm
Location: Belgium

Re: double/long double printing code

Post by Creature »

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.
User avatar
Solar
Member
Member
Posts: 7615
Joined: Thu Nov 16, 2006 12:01 pm
Location: Germany
Contact:

Re: double/long double printing code

Post by Solar »

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.
User avatar
01000101
Member
Member
Posts: 1599
Joined: Fri Jun 22, 2007 12:47 pm
Contact:

Re: double/long double printing code

Post by 01000101 »

Combuster wrote:

Code: Select all

    // 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.

Solar: Thanks, I'll look for those.
Post Reply