lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]



As part of my ARM-linux adaptation work (see other msg) I did the attached 'float2str()' code. It's a quickie, and I'd want to replace it with (a similar sized) tested & proven Open Source approach. But is there any?

ucLinux etc. must have some, but I don't want to drag in a whole 'printf()' clone just for this. Any pointers or ideas are welcome.

(also, if you want to use my code, go right ahead.. MIT/X11 licensed)


//
// FLT2STR.C                Copyright (c) 2004, Asko Kauppi
//
// Simple 'printf()' replacement for converting floating point numbers
// to a string. This is needed i.e. by ARM Linux variants, where the
// stock 'printf()' seemed to be faulty (Scratchbox 0.9.8.3 + QEMU).
//
// Although such system issues might be fixed, it's not a bad idea
// to have an easy 'printf()' replacement up in the sleeve.. :)
//
// Wanted: Proper, proven Open Source code that handles this.
//
#define DIGIT_DEPTH_REGULAR 5   // "%.5g"
#define DIGIT_DEPTH_EXP 9       // how many meaningful digits are there?

#define EXP_MAX_LIMIT (1e9)   // >= this uses e+N notation
#define EXP_MIN_LIMIT (1e-9)  // <= this uses e-N

// Max output length:
// -900000000.12345 = ca. 16 chars + end
// -2.123456789e+99
//
#include <math.h>
#include <stdio.h>
#include <assert.h>

//====================================================

// Note: This is _not_ for double's since there were other issues
//       with them in the aforementioned Linux system.
//
void float2str( char* buf, float val )
{
long vl;
int exp=0;
int vi;
int digit_depth= DIGIT_DEPTH_REGULAR;
const char* buf0= buf;

    assert(buf);  // also assumes 'enough' length in the buffer

    if (val<0.0)
        { *buf++='-'; val=-val; }

    if ( (val <= EXP_MIN_LIMIT) || (val >= EXP_MAX_LIMIT) )   // use exponent notation?
        {
        exp= (int)log10f(val);
        val /= powf(10.0,exp);
        
        assert( (-99 <= exp) && (exp <= 99) );
        
        digit_depth= DIGIT_DEPTH_EXP;
        }

    // Rounding is very necessary (avoids 2.39999)
    //
    val += 0.5 * pow(10.0, -digit_depth);
    
    vl= (long)val;    // cuts off the fraction
    sprintf( buf, "%lu", vl );

    buf= strchr(buf,'\0');

    val -= vl;  // just decimals remain

    if (val > 1e-9)    // integer optimized
        {
        char* last_nonzero= buf-1;
        *buf++='.';
        
        while( digit_depth-- )
            {
            val *= 10.0;
            vi= ((int)val) %10;

            if (vi>0) last_nonzero= buf;    // remember last digit to keep

            *buf++ = '0'+vi;
            }
        *(last_nonzero+1)= '\0';    // cut tailing 0's away
        }

    if (exp)
        sprintf( buf, "e%+d", exp );
    
    assert( buf-buf0 < 25 );    // better die here..
}