120 lines
3.2 KiB
C
Executable File
120 lines
3.2 KiB
C
Executable File
/* strtofloat.c - Special number conversion for embedded Lua.
|
|
*
|
|
* FIXME - UPDATE THIS DOC!!!
|
|
* All Lua numbers fit into 32 bits, and depending on the context they are
|
|
* interpreted as signed integers or signle precision floats.
|
|
*
|
|
* The problem is that if we need to figure out if the number being converted
|
|
* is an integer or a floating point number, so we have a special routine that
|
|
* returns a 32 bit value that can be formatted either way.
|
|
*
|
|
* If the source text has no decimal point, then the result is interpreted as
|
|
* an integer, otherwise we return a float.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <ctype.h>
|
|
|
|
#define MAX_DECIMAL_DIGITS 6
|
|
|
|
static const float pow10[MAX_DECIMAL_DIGITS] = {((float)1.0e-1), ((float)1.0e-2),
|
|
((float)1.0e-3), ((float)1.0e-4),
|
|
((float)1.0e-5), ((float)1.0e-6) };
|
|
// ((float)1.0e-7), ((float)1.0e-8) };
|
|
|
|
union float_long
|
|
{
|
|
float f;
|
|
long l;
|
|
};
|
|
|
|
// This function is only called when there is no chance that the string can be an
|
|
// integer...
|
|
|
|
float strtofloat(const char *s )
|
|
{
|
|
// union float_long val;
|
|
|
|
float decimal = (float)0.0;
|
|
float mantsign = (float)1.0; /* assume positive */
|
|
int expsign = 1;
|
|
|
|
int exp = 0;
|
|
int point = 0;
|
|
|
|
char i;
|
|
const float *fp;
|
|
|
|
// Scan past blanks
|
|
while (isspace(*s))
|
|
++s;
|
|
|
|
switch( *s )
|
|
{
|
|
case '-': mantsign = (float)-1.0; // Note fallthrough to increment!
|
|
case '+': s++;
|
|
}
|
|
|
|
// Now we're pointing at the first digits, so convert to a number
|
|
// until we reach a non-digit
|
|
|
|
for( decimal = 0; isdigit(i = *s); ++s )
|
|
decimal = (decimal * 10) + (i - '0');
|
|
|
|
// Now we're done converting a string of digits, and we may be
|
|
// done, but check for a decimal point and convert any digits
|
|
// after that...
|
|
|
|
if (*s == '.')
|
|
{
|
|
// We've got a decimal point! So increment past it and convert the
|
|
// part after the decimal point...
|
|
|
|
point = 1;
|
|
|
|
for( ++s, fp = &pow10[0]; isdigit(i = *s) && (fp < &pow10[MAX_DECIMAL_DIGITS]); ++s )
|
|
{
|
|
decimal = decimal + (*fp++ * (i - '0'));
|
|
}
|
|
|
|
// We've got all the significant digits we can use - scan past the rest
|
|
// of the digits if any...
|
|
|
|
while (isdigit(*s)) /* scan past insignificant digits */
|
|
++s;
|
|
}
|
|
|
|
// Now we're done converting all the decimal digits, and we may be
|
|
// done, but check for an exponent and covert digits after that...
|
|
|
|
if (tolower(*s) == 'e')
|
|
{
|
|
// We've got either an E or an e, so skip past it and look for a
|
|
// sign character...
|
|
++s;
|
|
|
|
switch( *s )
|
|
{
|
|
case '-': expsign = -1; // Note fallthrough to increment!
|
|
case '+': s++;
|
|
}
|
|
|
|
// Now convert all of the exponent digits
|
|
|
|
//, but first add the decimal part
|
|
// of the number to the value so far...
|
|
// val.f = (val.l * ((float)1.0)) + decimal;
|
|
|
|
for( exp = 0; isdigit(i = *s); ++s )
|
|
exp = (exp * 10) + (i - '0');
|
|
|
|
// And now scale the result - do it using brute force division or
|
|
// multiplication by 10
|
|
|
|
while( 0 != exp-- )
|
|
decimal = decimal * (1 == expsign ? ((float)10.0) : ((float)0.1));
|
|
}
|
|
|
|
return( decimal * mantsign );
|
|
}
|