/*============================================================================= Name : fastmath.c Purpose : Provides generic fast math routines Created 9/9/1997 by gshaw Copyright Relic Entertainment, Inc. All rights reserved. =============================================================================*/ #include #include #include "types.h" #include "fastmath.h" #include "debug.h" #if 0 real32 fmathSqrtGS(real32 num) { real32 x = num; sdword *exp = (sdword *)&x; sdword modexp = *exp; modexp >>= 23; modexp &= 255; modexp -= 127; modexp >>= 1; modexp += 127; modexp <<= 23; *exp = (*exp & 0x807fffff) | modexp; x = 0.5f * (x + num/x); x = 0.5f * (x + num/x); return x; } #endif /* MOST_SIG_OFFSET gives the (int *) offset from the address of the double * to the part of the number containing the sign and exponent. * You will need to find the relevant offset for your architecture. */ #define MOST_SIG_OFFSET 1 /* SQRT_TAB_SIZE - the size of the lookup table - must be a power of four. */ #define SQRT_TAB_SIZE 16384 /* MANT_SHIFTS is the number of shifts to move mantissa into position. * If you quadruple the table size subtract two from this constant, * if you quarter the table size then add two. * Valid values are: (16384, 7) (4096, 9) (1024, 11) (256, 13) */ #define MANT_SHIFTS 7 #define EXP_BIAS 1023 /* Exponents are always positive */ #define EXP_SHIFTS 20 /* Shifs exponent to least sig. bits */ #define EXP_LSB 0x00100000 /* 1 << EXP_SHIFTS */ #define MANT_MASK 0x000FFFFF /* Mask to extract mantissa */ static int fmathsqrt_tab[SQRT_TAB_SIZE]; void fmathInitSqrt() { int i; double f; unsigned int *fi = (unsigned int *) &f + MOST_SIG_OFFSET; for (i = 0; i < SQRT_TAB_SIZE/2; i++) { f = 0; /* Clears least sig part */ *fi = (i << MANT_SHIFTS) | (EXP_BIAS << EXP_SHIFTS); f = sqrt(f); fmathsqrt_tab[i] = *fi & MANT_MASK; f = 0; /* Clears least sig part */ *fi = (i << MANT_SHIFTS) | ((EXP_BIAS + 1) << EXP_SHIFTS); f = sqrt(f); fmathsqrt_tab[i + SQRT_TAB_SIZE/2] = *fi & MANT_MASK; } } double fmathSqrtDouble(double f) { unsigned int e; unsigned int *fi = (unsigned int *) &f + MOST_SIG_OFFSET; #if 0 double test = sqrt(f); double test2 = (double)fmathSqrtGS((real32)f); double error; #endif if (f == 0.0) { return 0.0; } e = (*fi >> EXP_SHIFTS) - EXP_BIAS; *fi &= MANT_MASK; if (e & 1) *fi |= EXP_LSB; e >>= 1; *fi = (fmathsqrt_tab[*fi >> MANT_SHIFTS]) | ((e + EXP_BIAS) << EXP_SHIFTS); #if 0 dbgAssert(f > 0.0f); error = abs((f - test) / test); if (error > 0.0001) { dbgAssert(FALSE); } dbgAssert(!_isnan(f)); #endif return f; } void fmathInit() { fmathInitSqrt(); }