Thread: Anyone knows how I can convert a float/double to string?

1. Anyone knows how I can convert a float/double to string?

I want to do what the title says but without using any built-in functions. Anyone has any idea how I can do that? I made my research but I wasn't able to find a clear source that will post the source code. 2. Why do you need to do it without a library?

sourceware.org Git - glibc.git/summary
It'll be buried somewhere in there.

But be warned, float to string conversion is a messy business at the best of times, with lots of corner cases.
Production quality code that's been optimised for years on end (such as glibc) will be a PITA to read and comprehend. 3. Originally Posted by Salem Why do you need to do it without a library?

sourceware.org Git - glibc.git/summary
It'll be buried somewhere in there.

But be warned, float to string conversion is a messy business at the best of times, with lots of corner cases.
Production quality code that's been optimised for years on end (such as glibc) will be a PITA to read and comprehend.
I mean I was kinda afraid than in the end I'll have to read the ugly libc code but still I didn't lose anything to ask. I'm writing it myself because the language I want to use doesn't have a system library and someone has to write one. Tho I would like to use a system library as I don't like libc. ESPECIALLY GLIBC!!!! Thanks for your time man! 4. The algorithms are complicated. Keep in mind that floating point structure, in modern computers, follow the IEEE 754 model, where the value is stored as 3 unsigned integers following not ONE but TWO possible formulas: And, for E=Emax, there are NANs... Notice the values are in base 2, not 10. S (1 bit), F (p-1 bits) and E (n bits, 8 for float, 11 for double and 15 for long double)... p is the precision, in bits (24 for float, 53 for double and 64 for long double). Ebias is 127 for float, 1023 for double and 16383 for long double.

But if you want a generic approach, there are other representations of floating point in the wild you have to account for.

In your scenario, if you don't want to use ANY external libraries, ALL floating point functions declared in math.h, all I/O functions in stdio.h, all library functions in string.h and stdlib.h, limits on limits.h and float.h are gone. You have to do it yourself.

You can separate the integer part from the fractional and print it (but beware: since float has E, normalized, can have E=Emax-1, or E=254, the expoent is 127, (and the value is scaled by 2¹²⁷, as a 128 bits long integer)... Double, using 11 bits as expoent has a scaling factor of 1024 bits long, long double, 16384 bits long! None of these sizes can be used with int, long or long long objects! Here I am considering only those values scaled up to form big integer values.

After that, you can multiply the fractional part by 10, get the integer part and subtract it, keeping in loop until get zero (or until you are satisfied)... Exemple:

Code:
0.725 * 10 = 7.25 (print 7 and keep 0.25
0.25 * 10 = 2.5 (print 2 and keep 0.5)
0.5 * 10 = 5.0 ( print 5 and keep 0.0 )
0.0 (end) 5. If you want some papers to study some refined algorithms for floating point printing. Here are some:

Ryü - Fast Float-to-String Conversion
Printing Floating-Point Numbers Accurately with Integers
How to print floating-point numbers accurately 6. Originally Posted by flp1969 If you want some papers to study some refined algorithms for floating point printing. Here are some:

Ryü - Fast Float-to-String Conversion
Printing Floating-Point Numbers Accurately with Integers
How to print floating-point numbers accurately
Thanks a lot! 7. Originally Posted by flp1969 The algorithms are complicated. Keep in mind that floating point structure, in modern computers, follow the IEEE 754 model, where the value is stored as 3 unsigned integers following not ONE but TWO possible formulas: And, for E=Emax, there are NANs... Notice the values are in base 2, not 10. S (1 bit), F (p-1 bits) and E (n bits, 8 for float, 11 for double and 15 for long double)... p is the precision, in bits (24 for float, 53 for double and 64 for long double). Ebias is 127 for float, 1023 for double and 16383 for long double.

But if you want a generic approach, there are other representations of floating point in the wild you have to account for.

In your scenario, if you don't want to use ANY external libraries, ALL floating point functions declared in math.h, all I/O functions in stdio.h, all library functions in string.h and stdlib.h, limits on limits.h and float.h are gone. You have to do it yourself.

You can separate the integer part from the fractional and print it (but beware: since float has E, normalized, can have E=Emax-1, or E=254, the expoent is 127, (and the value is scaled by 2¹²⁷, as a 128 bits long integer)... Double, using 11 bits as expoent has a scaling factor of 1024 bits long, long double, 16384 bits long! None of these sizes can be used with int, long or long long objects! Here I am considering only those values scaled up to form big integer values.

After that, you can multiply the fractional part by 10, get the integer part and subtract it, keeping in loop until get zero (or until you are satisfied)... Exemple:

Code:
0.725 * 10 = 7.25 (print 7 and keep 0.25
0.25 * 10 = 2.5 (print 2 and keep 0.5)
0.5 * 10 = 5.0 ( print 5 and keep 0.0 )
0.0 (end)
Lol, I understand now. It seems very complex. Thanks a lot! 8. An example without using functions from libc:
Code:
static inline void putstr( const void *ptr, unsigned int size )
{
// x86-64:
// OBS: `syscall` can clobber RCX!
__asm__ __volatile__ (
"syscall"
: : "a" (1), "D" (1), "S" (ptr), "d" (size)
: "memory", "rcx"
);

// i386:
//__asm__ __volatile__ (
//  "int 0x80"
//  : : "a" (4), "b" (1), "c" (ptr), "d" (size)
//  : "memory"
//);

// arm (aarch32) -- change R0 to 64 for aarch64.
//__asm__ __volatile__ (
//  "svc \$0"
//  : : "r7" (4), "r0" (1), "r1" (ptr), "r2" (size)
//  : "memory"
//);
}

static inline void putchr( char c ) { putstr( &c, 1 ); }

// Prints a decimal unsigned value (64 bits).
__attribute__((noinline))
void printu( unsigned long long int x )
{
char a;
char *p, *endp;

p = endp = a + sizeof a;
do {
*--p =  '0' + (x % 10);
} while ( x /= 10 );

putstr( p, endp - p );
}

static void printfrac( float x )
{
// This will fail if integer part > 2³²-1.
x -= (unsigned long long int)x;

do {
int i;    // i < 10 always.

x *= 10.0f;
i = x;
putchr( '0' + i );
x -= i;
} while ( x != 0.0f );
}

__attribute__((noinline))
void printflt( float x )
{
static const char c = '.';

// is value negative?
if ( x < 0.0f )
{
static const char c = '-';

putchr( '-' );
x = -x;
}

// Gets the integer part and print.
// This will fail if the integer part is greater than 2⁶⁴-1.
printu( x );

putchr( '.' );

printfrac( x );
}

// Test!
int main( void )
{
printflt( 3.14f );
putchr( '\n' );
} 9. Originally Posted by flp1969 An example without using functions from libc:
Code:
static inline void putstr( const void *ptr, unsigned int size )
{
// x86-64:
// OBS: `syscall` can clobber RCX!
__asm__ __volatile__ (
"syscall"
: : "a" (1), "D" (1), "S" (ptr), "d" (size)
: "memory", "rcx"
);

// i386:
//__asm__ __volatile__ (
//  "int 0x80"
//  : : "a" (4), "b" (1), "c" (ptr), "d" (size)
//  : "memory"
//);

// arm (aarch32) -- change R0 to 64 for aarch64.
//__asm__ __volatile__ (
//  "svc \$0"
//  : : "r7" (4), "r0" (1), "r1" (ptr), "r2" (size)
//  : "memory"
//);
}

static inline void putchr( char c ) { putstr( &c, 1 ); }

// Prints a decimal unsigned value (64 bits).
__attribute__((noinline))
void printu( unsigned long long int x )
{
char a;
char *p, *endp;

p = endp = a + sizeof a;
do {
*--p =  '0' + (x % 10);
} while ( x /= 10 );

putstr( p, endp - p );
}

static void printfrac( float x )
{
// This will fail if integer part > 2³²-1.
x -= (unsigned long long int)x;

do {
int i;    // i < 10 always.

x *= 10.0f;
i = x;
putchr( '0' + i );
x -= i;
} while ( x != 0.0f );
}

__attribute__((noinline))
void printflt( float x )
{
static const char c = '.';

// is value negative?
if ( x < 0.0f )
{
static const char c = '-';

putchr( '-' );
x = -x;
}

// Gets the integer part and print.
// This will fail if the integer part is greater than 2⁶⁴-1.
printu( x );

putchr( '.' );

printfrac( x );
}

// Test!
int main( void )
{
printflt( 3.14f );
putchr( '\n' );
}
Well... Thanks a lot!!! This doesn't look so crazy as looking and understanding complex formulas or searching the 1.3M LoC Glibc's source code. Have a great day my friend! Popular pages Recent additions code, idea, made, research, source 