Quick & Dirty float to string converter

The following code sample will convert IEEE-754 32bit float/double as used in C18 to a string. There are some limitations, but it runs ok on my unix box. I haven’t (and cannot at the moment) try this on PIC18F/RC. The hex binary test values were obtained by creating and populating a float variable under MPLAB and hand copying out the hex value for testing purposes. The unix box is native 64bit, so I may have messed up somewhere but thought I’d drop this 5-minute QnD code out for folks to look at/use if needed or wanted. I’m sure there is a better way, but its just Quick 'n Dirty so don’t expect elegant/optimal/all-encompassing.

When run on unix it generates what looks like reasonable output:

alpha> ./printff
1.234567879
1.233999963
1234.000000000
1234567936.000000000
0.123399970
0.001233931
0.000012276

Should work with printff( (long)float-variable-name ).

Bud
PS Derived by reading http://en.wikipedia.org/wiki/IEEE_754

#include <stdio.h>

int main()
{
    printff( 0x3f9e0652 );	/* 	f1 = 1.23456789;	*/
    printff( 0x3f9df3b6 );	/*      f1 = 1.234		*/
    printff( 0x449a4000 );	/*      f1 = 1234.0		*/
    printff( 0x4e932c06 );	/*      f1 = 123456789.0        */
    printff( 0x3dfcb924 );	/*      f1 = 0.1234             */
    printff( 0x3aa1be2b );      /*      f1 = 0.001234           */
    printff( 0x374f07e5 );      /*      f1 = 0.00001234         */
}

void printff( long fbinary )
{
unsigned char sign;
unsigned char exp;
unsigned long mantissa;
int bits;
long whole;
long fraction;
long left;

    sign = 1;
    if ((fbinary & 0x80000000) != 0) sign = -1;
    exp = (fbinary & 0x7F800000) >> 23;
    mantissa = (fbinary & 0x007FFFFF);

    bits = (int)exp - (int)127;
    if (bits >= 0)
    {
        if (bits <= 30)
        {
	    whole = 0x1;
	    while (bits > 0)
	    {
	        whole <<= 1;
	        if ((mantissa & 0x00400000) != 0)
		    whole |= 0x1;
	        mantissa <<= 1;
	        --bits;
	    }
            printf( "%c%d.", ((sign == 1)?' ':'-'), whole );
        }
        else
        {
	    // can't do yet
	    printf( "**.****
");
        }

        fraction = 0;
        left     = 500000000;
        while (mantissa != 0)
        {
	    if ((mantissa & 0x00400000) != 0)
	        fraction += left;
	    mantissa <<= 1;
	    left = left / 2;
        }
        printf( "%09d
", fraction );
    }
    else
    {
        /* Number < 1.0 */
        printf( "%c0.", ((sign == 1)?' ':'-') );
	mantissa |= 0x00800000;
	bits = -bits;
	if (bits < 24 )
	{
	    mantissa >>= bits;
            fraction = 0;
            left     = 500000000;
            while (mantissa != 0)
            {
	        if ((mantissa & 0x00800000) != 0)
	            fraction += left;
	        mantissa <<= 1;
	        left = left / 2;
            }
            printf( "%09d
", fraction );
	}
	else
	{
	    printf( "%09d
", 0 );
	}
    }
    return;
}

nice job man, im sure it would be useful.

Fixed a couple bugs.

Test cases run:
1.234567879
1.233999963
1234.000000000
1234567936.000000000
0.123399970
0.001233990
0.000012335
0.156250000
98.765434262
9.876543043
0.987654324


void printff( long fbinary )
{
char sign;
unsigned char exp;
int bias;
long data;
long left;

    sign = ' ';
    if ((fbinary & 0x80000000) != 0) sign = '-';

    exp = (fbinary & 0x7F800000) >> 23; 

    /* compute whole number */
    bias = (int)exp - (int)127;
    if (bias >= 0)
    {
        if (bias <= 30)
        {
	    data = 0x1;
	    while (bias > 0)
	    {
	        data <<= 1;
	        if ((fbinary & 0x00400000) != 0)
		    data |= 0x1;
	        fbinary <<= 1;
	        --bias;
	    }
            printf( "%c%d.", sign, data );
        }
        else
        {
	    // can't do yet
	    printf( "**.****
");
	    return;
        }

	/* compute fraction */
        data = 0;
        left = 500000000;
	fbinary &= 0x007FFFFF;
        while (fbinary != 0)
        {
	    if ((fbinary & 0x00400000) != 0)
	        data += left;
	    fbinary <<= 1;
	    fbinary &= 0x007FFFFF;
	    left = left >> 1;
        }
        printf( "%09d
", data );
    }
    else
    {
        /* Number < 1.0 */
        printf( "%c0.", sign );
	bias = -bias;
	if (bias < 24 )
	{
            data = 0;
            left = 500000000;
	    fbinary &= 0x00FFFFFF;
	    fbinary |= 0x00800000;
	    fbinary >>= (bias-1);
            while (fbinary != 0)
            {
	        if ((fbinary & 0x00800000) != 0)
	            data += left;
	        fbinary <<= 1;
	        fbinary &= 0x00FFFFFF;
		left = left >> 1;
            }
            printf( "%09d
", data );
	}
	else
	{
	    printf( "%09d
", 0 );
	}
    }
    return;
}

PS I’m not trying to encourage the use of floating point, but for debugging and in small doses it has its uses.