Chief Delphi

Chief Delphi (http://www.chiefdelphi.com/forums/index.php)
-   Programming (http://www.chiefdelphi.com/forums/forumdisplay.php?f=51)
-   -   Quick & Dirty float to string converter (http://www.chiefdelphi.com/forums/showthread.php?t=55105)

dcbrown 28-02-2007 18:02

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


Code:

#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( "**.****\n");
        }

        fraction = 0;
        left    = 500000000;
        while (mantissa != 0)
        {
            if ((mantissa & 0x00400000) != 0)
                fraction += left;
            mantissa <<= 1;
            left = left / 2;
        }
        printf( "%09d\n", 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\n", fraction );
        }
        else
        {
            printf( "%09d\n", 0 );
        }
    }
    return;
}


Uberbots 03-03-2007 18:34

Re: Quick & Dirty float to string converter
 
nice job man, im sure it would be useful.

dcbrown 05-03-2007 14:59

Re: Quick & Dirty float to string converter
 
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


Code:

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( "**.****\n");
            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\n", 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\n", data );
        }
        else
        {
            printf( "%09d\n", 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.


All times are GMT -5. The time now is 00:24.

Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2017, Jelsoft Enterprises Ltd.
Copyright © Chief Delphi