[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: better float2str() C code, anyone?
- From: Asko Kauppi <asko.kauppi@...>
- Date: Tue, 30 Nov 2004 12:06:19 +0200
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..
}