00001 /* 00002 * PROPRIETARY INFORMATION. This software is proprietary to 00003 * Side Effects Software Inc., and is not to be reproduced, 00004 * transmitted, or disclosed in any way without written permission. 00005 * 00006 * Produced by: 00007 * PROGRAMMER 00008 * Side Effects Software Inc. 00009 * 20 Maud St. 00010 * Toronto, Ontario, M5V 2M5 00011 * Canada 00012 * 416-366-4607 00013 * 00014 * NAME: SYS_Floor (C++) 00015 * 00016 * COMMENTS: Fast floating point floor function (faster than floorf) 00017 * There are two versions, a fast inline and a slower (but 00018 * still faster than floorf) out-lined function. 00019 * 00020 */ 00021 00022 #ifndef __SYS_Floor_H__ 00023 #define __SYS_Floor_H__ 00024 00025 #include "SYS_API.h" 00026 #include <math.h> 00027 #include "SYS_Types.h" 00028 00029 SYS_API extern fpreal32 SYSfloor(fpreal32 val); 00030 SYS_API extern fpreal32 SYSceil(fpreal32 val); 00031 SYS_API extern fpreal32 SYSfrac(fpreal32 val); 00032 SYS_API extern fpreal64 SYSfrac(fpreal64 val); 00033 SYS_API extern fpreal64 SYSniceNumber(fpreal64 num, int digits = 6); 00034 00035 static inline fpreal32 SYSniceNumber(fpreal32 num, int digits = 6) 00036 { return (fpreal32)SYSniceNumber((fpreal64)num, digits);} 00037 00038 static inline fpreal64 SYSfloor(fpreal64 a) { return floor(a); } 00039 static inline fpreal64 SYSceil(fpreal64 a) { return ceil(a); } 00040 00041 static inline int32 00042 SYSfastFloor(fpreal32 a) { return a < 0 ? (int32)a - 1 : (int32)a; } 00043 00044 static inline int64 00045 SYSfastFloor(fpreal64 a) { return a < 0 ? (int64)a - 1 : (int64)a; } 00046 00047 // 00048 // The following function splits a floating point value into its fractional and 00049 // integer components. The integer returned is the floor() of the fractional 00050 // value, while the fractional component is guaranteed to always be in the 00051 // range [0, 1). This is different from (val - floor(val)) which can cause 00052 // problems if the value is very close to -0. 00053 // 00054 SYS_API extern void SYSsplitFloat(fpreal32 &val, int &ival); 00055 SYS_API extern void SYSsplitFloat(fpreal32 &val, fpreal32 &ival); 00056 00057 // fastSplitFloat() is not as correct as the above code. Using the fast 00058 // version, you can get somewhat unexpected results. However, in many cases, 00059 // it's quite acceptable to get these results. 00060 // a) Denormalization of -ve values close to zero (i.e. -1e-10) will result 00061 // in the fractional value being 1.0 exactly and the integer value = -1 00062 static inline void 00063 SYSfastSplitFloat(fpreal32 &val, int32 &ival) 00064 { 00065 ival = SYSfastFloor(val); 00066 val -= (fpreal32)ival; 00067 } 00068 00069 static inline void 00070 SYSfastSplitFloat(fpreal64 &val, int64 &ival) 00071 { 00072 ival = SYSfastFloor(val); 00073 val -= (fpreal64)ival; 00074 } 00075 00076 inline fpreal32 00077 SYSfloorIL(fpreal32 val) 00078 { 00079 SYS_FPReal32Union tmp; 00080 register unsigned shift; 00081 00082 tmp.fval = val; 00083 shift = (tmp.uval >> 23) & 0xff; 00084 00085 if (shift < 0x7f) 00086 { 00087 tmp.fval = (tmp.uval > 0x80000000) ? -1.0F : 0.0F; 00088 } 00089 else if (shift < 0x96) 00090 { 00091 register unsigned mask = 0xffffffff << (0x96 - shift); 00092 if (tmp.uval & 0x80000000) 00093 { 00094 if ((tmp.uval & ~mask) & 0x7fffff) 00095 { 00096 tmp.uval &= mask; 00097 tmp.fval--; 00098 } 00099 } 00100 else tmp.uval &= mask; 00101 } 00102 return tmp.fval; 00103 } 00104 00105 inline fpreal64 SYSfloorIL(fpreal64 val) { return SYSfloor(val); } 00106 inline fpreal32 SYSceilIL(fpreal32 val) { return SYSceil(val); } 00107 inline fpreal64 SYSceilIL(fpreal64 val) { return SYSceil(val); } 00108 00109 inline fpreal32 00110 SYSfracIL(fpreal32 val) 00111 { 00112 // On Intel chips, val may be a double precision register value. In this 00113 // case, a small value less than zero will cause the fractional result to 00114 // be outside the range [0-1), which is obviously invalid. Thus, we have 00115 // to have special code to handle this case properly. On non-intel chips, 00116 // which support floating point operations, we can simply de-normalize the 00117 // value and return the fractional component properly. 00118 #if defined(WIN32) || defined(LINUX) 00119 val = val - SYSfloorIL(val); 00120 return (val < 0 || val >= 1) ? 0 : val; 00121 #else 00122 val += 1; // Normalize fpreal32 first 00123 return val - SYSfloorIL(val); 00124 #endif 00125 } 00126 00127 inline fpreal64 00128 SYSfracIL(fpreal64 val) 00129 { 00130 return SYSfrac(val); 00131 } 00132 00133 inline fpreal32 00134 SYSrint(fpreal32 val) 00135 { 00136 return SYSfloorIL(val + 0.5F); 00137 } 00138 00139 inline fpreal64 00140 SYSrint(fpreal64 val) 00141 { 00142 return SYSfloor(val + 0.5); 00143 } 00144 00145 00146 #endif
1.5.9