From fe4829a0fa9647e94011df58621a5982df2cd7e8 Mon Sep 17 00:00:00 2001 From: Ben Millwood Date: Fri, 6 Apr 2012 21:33:24 +0000 Subject: * Calculate some exponentiation more efficiently/sensibly in bg_lib.c --- src/game/bg_lib.c | 106 +++++++++++++++++++++++------------------------------- 1 file changed, 44 insertions(+), 62 deletions(-) (limited to 'src/game') diff --git a/src/game/bg_lib.c b/src/game/bg_lib.c index dd31e946..94af5f18 100644 --- a/src/game/bg_lib.c +++ b/src/game/bg_lib.c @@ -818,6 +818,43 @@ double rint( double v ) return floor( v ); } +/* +=============== +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 ) { return sin( x ) / cos( x ); @@ -1540,28 +1577,8 @@ double strtod( const char *nptr, char **endptr ) *endptr = (char *)nptr; return res; } - if( exp > 0 ) - { - 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; - } - } + + res *= powN( 2, exp ); } if( endptr ) *endptr = (char *)end; @@ -1604,30 +1621,8 @@ double strtod( const char *nptr, char **endptr ) *endptr = (char *)nptr; return res; } - if( exp > 0 ) - { - 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; - } - } + + res *= powN( 10, exp ); } if( endptr ) *endptr = (char *)end; @@ -2540,19 +2535,6 @@ static LDOUBLE abs_val (LDOUBLE value) return result; } -static LDOUBLE pow10 (int exp) -{ - LDOUBLE result = 1; - - while (exp) - { - result *= 10; - exp--; - } - - return result; -} - static long round (LDOUBLE value) { long intpart; @@ -2615,12 +2597,12 @@ static int fmtfp (char *buffer, size_t *currlen, size_t maxlen, /* We "cheat" by converting the fractional part to integer by * 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++; - fracpart -= pow10 (max); + fracpart -= powN (10, max); } #ifdef DEBUG_SNPRINTF -- cgit