mirror of
https://github.com/UberGames/lilium-voyager.git
synced 2025-01-31 11:20:32 +00:00
More intelligent exponentiation in strtod/strtol (#5487) - patch by Ben Millwood
This commit is contained in:
parent
8534c94e4c
commit
ca44693f34
1 changed files with 44 additions and 64 deletions
|
@ -768,6 +768,43 @@ double atan2( double y, double x ) {
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
===============
|
||||||
|
powN
|
||||||
|
|
||||||
|
Raise a double to a integer power
|
||||||
|
===============
|
||||||
|
*/
|
||||||
|
static double powN( double base, int exp )
|
||||||
|
{
|
||||||
|
if( exp >= 0 )
|
||||||
|
{
|
||||||
|
double result = 1.0;
|
||||||
|
|
||||||
|
// calculate x, x^2, x^4, ... by repeated squaring
|
||||||
|
// and multiply together the ones corresponding to the
|
||||||
|
// binary digits of the exponent
|
||||||
|
// e.g. x^73 = x^(1 + 8 + 64) = x * x^8 * x^64
|
||||||
|
while( exp > 0 )
|
||||||
|
{
|
||||||
|
if( exp % 2 == 1 )
|
||||||
|
result *= base;
|
||||||
|
|
||||||
|
base *= base;
|
||||||
|
exp /= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// if exp is INT_MIN, the next clause will be upset,
|
||||||
|
// because -exp isn't representable
|
||||||
|
else if( exp == INT_MIN )
|
||||||
|
return powN( base, exp + 1 ) / base;
|
||||||
|
// x < 0
|
||||||
|
else
|
||||||
|
return 1.0 / powN( base, -exp );
|
||||||
|
}
|
||||||
|
|
||||||
double tan( double x ) {
|
double tan( double x ) {
|
||||||
return sin(x) / cos(x);
|
return sin(x) / cos(x);
|
||||||
}
|
}
|
||||||
|
@ -1042,7 +1079,6 @@ double strtod( const char *nptr, char **endptr )
|
||||||
if( end != s && tolower( *nptr ) == 'p' )
|
if( end != s && tolower( *nptr ) == 'p' )
|
||||||
{
|
{
|
||||||
int exp;
|
int exp;
|
||||||
float res2;
|
|
||||||
// apparently (confusingly) the exponent should be
|
// apparently (confusingly) the exponent should be
|
||||||
// decimal
|
// decimal
|
||||||
exp = strtol( &nptr[1], (char **)&end, 10 );
|
exp = strtol( &nptr[1], (char **)&end, 10 );
|
||||||
|
@ -1053,28 +1089,8 @@ double strtod( const char *nptr, char **endptr )
|
||||||
*endptr = (char *)nptr;
|
*endptr = (char *)nptr;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if( exp > 0 )
|
|
||||||
{
|
res *= powN( 2, exp );
|
||||||
while( exp-- > 0 )
|
|
||||||
{
|
|
||||||
res2 = res * 2;
|
|
||||||
// check for infinity
|
|
||||||
if( res2 <= res )
|
|
||||||
break;
|
|
||||||
res = res2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
while( exp++ < 0 )
|
|
||||||
{
|
|
||||||
res2 = res / 2;
|
|
||||||
// check for underflow
|
|
||||||
if( res2 >= res )
|
|
||||||
break;
|
|
||||||
res = res2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if( endptr )
|
if( endptr )
|
||||||
*endptr = (char *)end;
|
*endptr = (char *)end;
|
||||||
|
@ -1108,7 +1124,6 @@ double strtod( const char *nptr, char **endptr )
|
||||||
if( p != end && tolower( *nptr ) == 'e' )
|
if( p != end && tolower( *nptr ) == 'e' )
|
||||||
{
|
{
|
||||||
int exp;
|
int exp;
|
||||||
float res10;
|
|
||||||
exp = strtol( &nptr[1], (char **)&end, 10 );
|
exp = strtol( &nptr[1], (char **)&end, 10 );
|
||||||
if( &nptr[1] == end )
|
if( &nptr[1] == end )
|
||||||
{
|
{
|
||||||
|
@ -1117,30 +1132,8 @@ double strtod( const char *nptr, char **endptr )
|
||||||
*endptr = (char *)nptr;
|
*endptr = (char *)nptr;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if( exp > 0 )
|
|
||||||
{
|
res *= powN( 10, exp );
|
||||||
while( exp-- > 0 )
|
|
||||||
{
|
|
||||||
res10 = res * 10;
|
|
||||||
// check for infinity to save us time
|
|
||||||
if( res10 <= res )
|
|
||||||
break;
|
|
||||||
res = res10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if( exp < 0 )
|
|
||||||
{
|
|
||||||
while( exp++ < 0 )
|
|
||||||
{
|
|
||||||
res10 = res / 10;
|
|
||||||
// check for underflow
|
|
||||||
// (test for 0 would probably be just
|
|
||||||
// as good)
|
|
||||||
if( res10 >= res )
|
|
||||||
break;
|
|
||||||
res = res10;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if( endptr )
|
if( endptr )
|
||||||
*endptr = (char *)end;
|
*endptr = (char *)end;
|
||||||
|
@ -1907,19 +1900,6 @@ static LDOUBLE abs_val (LDOUBLE value)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static LDOUBLE pow10 (int exp)
|
|
||||||
{
|
|
||||||
LDOUBLE result = 1;
|
|
||||||
|
|
||||||
while (exp)
|
|
||||||
{
|
|
||||||
result *= 10;
|
|
||||||
exp--;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static long round (LDOUBLE value)
|
static long round (LDOUBLE value)
|
||||||
{
|
{
|
||||||
long intpart;
|
long intpart;
|
||||||
|
@ -1982,12 +1962,12 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen,
|
||||||
/* We "cheat" by converting the fractional part to integer by
|
/* We "cheat" by converting the fractional part to integer by
|
||||||
* multiplying by a factor of 10
|
* multiplying by a factor of 10
|
||||||
*/
|
*/
|
||||||
fracpart = round ((pow10 (max)) * (ufvalue - intpart));
|
fracpart = round ((powN (10, max)) * (ufvalue - intpart));
|
||||||
|
|
||||||
if (fracpart >= pow10 (max))
|
if (fracpart >= powN (10, max))
|
||||||
{
|
{
|
||||||
intpart++;
|
intpart++;
|
||||||
fracpart -= pow10 (max);
|
fracpart -= powN (10, max);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef DEBUG_SNPRINTF
|
#ifdef DEBUG_SNPRINTF
|
||||||
|
|
Loading…
Reference in a new issue