BEAST/BSE - Better Audio System and Sound Engine
0.8.2
|
00001 // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html 00002 #ifndef __BSE_IEEE754_H__ 00003 #define __BSE_IEEE754_H__ 00004 00005 #include <bse/bsedefs.hh> 00006 #include <math.h> /* signbit */ 00007 00008 /* override math.h definition of PI */ 00009 #undef PI 00010 #define PI (3.141592653589793238462643383279502884197) // pi 00011 00012 G_BEGIN_DECLS 00013 00014 /* IEEE 754 single precision floating point layout: 00015 * 31 30 23 22 0 00016 * +--------+---------------+---------------+ 00017 * | s 1bit | e[30:23] 8bit | f[22:0] 23bit | 00018 * +--------+---------------+---------------+ 00019 * B0------------------->B1------->B2-->B3--> 00020 * 00021 * IEEE 754 double precision floating point layout: 00022 * 63 62 52 51 32 31 0 00023 * +--------+----------------+----------------+ +---------------+ 00024 * | s 1bit | e[62:52] 11bit | f[51:32] 20bit | | f[31:0] 32bit | 00025 * +--------+----------------+----------------+ +---------------+ 00026 * B0--------------->B1---------->B2--->B3----> B4->B5->B6->B7-> 00027 */ 00028 00029 /* floating point type related constants */ 00030 #define BSE_FLOAT_BIAS (127) 00031 #define BSE_FLOAT_MAX_NORMAL (3.40282347e+38) /* 7f7fffff, 2^128 * (1 - BSE_FLOAT_EPSILON) */ 00032 #define BSE_FLOAT_MIN_NORMAL (1.17549435e-38) /* 00800000 */ 00033 #define BSE_FLOAT_MAX_SUBNORMAL (1.17549421e-38) /* 007fffff */ 00034 #define BSE_FLOAT_MIN_SUBNORMAL (1.40129846e-45) /* 00000001 */ 00035 #define BSE_FLOAT_EPSILON (5.9604644775390625e-08) /* 2^-24, round-off error at 1.0 */ 00036 #define BSE_DOUBLE_BIAS (1023) 00037 #define BSE_DOUBLE_MAX_NORMAL (1.7976931348623157e+308) /* 7fefffff ffffffff, 2^1024 * (1 - BSE_DOUBLE_EPSILON) */ 00038 #define BSE_DOUBLE_MIN_NORMAL (2.2250738585072014e-308) /* 00100000 00000000 */ 00039 #define BSE_DOUBLE_MAX_SUBNORMAL (2.2250738585072009e-308) /* 000fffff ffffffff */ 00040 #define BSE_DOUBLE_MIN_SUBNORMAL (4.9406564584124654e-324) /* 00000000 00000001 */ 00041 #define BSE_DOUBLE_EPSILON (1.1102230246251565404236316680908203125e-16) /* 2^-53, round-off error at 1.0 */ 00042 #define BSE_DOUBLE_INF (_bse_dinf_union.d) 00043 #define BSE_DOUBLE_NAN (_bse_dnan_union.d) 00044 #define BSE_FLOAT_INF (_bse_finf_union.f) 00045 #define BSE_FLOAT_NAN (_bse_fnan_union.f) 00046 00047 /* multiply with base2 exponent to get base10 exponent (for nomal numbers) */ 00048 #define BSE_LOG_2_BASE_10 (0.30102999566398119521) 00049 00050 /* the following macros work only on variables 00051 * and evaluate arguments multiple times 00052 */ 00053 00054 /* single precision value checks */ 00055 #define BSE_FLOAT_IS_ZERO(f) ((f) == 0.0) /* compiler knows this one */ 00056 #define BSE_FLOAT_IS_NORMAL(f) (BSE_FLOAT_PARTS (f).mpn.biased_exponent > 0 && \ 00057 BSE_FLOAT_PARTS (f).mpn.biased_exponent < 255) 00058 #define BSE_FLOAT_IS_SUBNORMAL(f) (BSE_FLOAT_PARTS (f).mpn.biased_exponent == 0 && \ 00059 BSE_FLOAT_PARTS (f).mpn.mantissa != 0) 00060 #define BSE_FLOAT_IS_NANINF(f) (BSE_FLOAT_PARTS (f).mpn.biased_exponent == 255) 00061 #define BSE_FLOAT_IS_NAN(f) (BSE_FLOAT_IS_NANINF (f) && BSE_FLOAT_PARTS (f).mpn.mantissa != 0) 00062 #define BSE_FLOAT_IS_INF(f) (BSE_FLOAT_IS_NANINF (f) && BSE_FLOAT_PARTS (f).mpn.mantissa == 0) 00063 #define BSE_FLOAT_IS_INF_POSITIVE(f) (BSE_FLOAT_IS_INF (f) && BSE_FLOAT_PARTS (f).mpn.sign == 0) 00064 #define BSE_FLOAT_IS_INF_NEGATIVE(f) (BSE_FLOAT_IS_INF (f) && BSE_FLOAT_PARTS (f).mpn.sign == 1) 00065 #ifdef signbit 00066 #define BSE_FLOAT_SIGN(f) (signbit (f)) 00067 #else 00068 #define BSE_FLOAT_SIGN(f) (BSE_FLOAT_PARTS (f).mpn.sign) 00069 #endif 00070 00071 /* double precision value checks */ 00072 #define BSE_DOUBLE_IS_ZERO(d) ((d) == 0.0) /* compiler knows this one */ 00073 #define BSE_DOUBLE_IS_NORMAL(d) (BSE_DOUBLE_PARTS (d).mpn.biased_exponent > 0 && \ 00074 BSE_DOUBLE_PARTS (d).mpn.biased_exponent < 2047) 00075 #define BSE_DOUBLE_IS_SUBNORMAL(d) (BSE_DOUBLE_PARTS (d).mpn.biased_exponent == 0 && \ 00076 (BSE_DOUBLE_PARTS (d).mpn.mantissa_low != 0 || \ 00077 BSE_DOUBLE_PARTS (d).mpn.mantissa_high != 0)) 00078 #define BSE_DOUBLE_IS_NANINF(d) (BSE_DOUBLE_PARTS (d).mpn.biased_exponent == 2047) 00079 #define BSE_DOUBLE_IS_NAN(d) (BSE_DOUBLE_IS_NANINF (d) && \ 00080 (BSE_DOUBLE_PARTS (d).mpn.mantissa_low != 0 || \ 00081 BSE_DOUBLE_PARTS (d).mpn.mantissa_high != 0)) 00082 #define BSE_DOUBLE_IS_INF(d) (BSE_DOUBLE_IS_NANINF (d) && \ 00083 BSE_DOUBLE_PARTS (d).mpn.mantissa_low == 0 && \ 00084 BSE_DOUBLE_PARTS (d).mpn.mantissa_high == 0) 00085 #define BSE_DOUBLE_IS_INF_POSITIVE(d) (BSE_DOUBLE_IS_INF (d) && BSE_DOUBLE_PARTS (d).mpn.sign == 0) 00086 #define BSE_DOUBLE_IS_INF_NEGATIVE(d) (BSE_DOUBLE_IS_INF (d) && BSE_DOUBLE_PARTS (d).mpn.sign == 1) 00087 #ifdef signbit 00088 #define BSE_DOUBLE_SIGN(d) (signbit (d)) 00089 #else 00090 #define BSE_DOUBLE_SIGN(d) (BSE_DOUBLE_PARTS (d).mpn.sign) 00091 #endif 00092 00093 /* --- denormal float handling --- */ 00094 static inline float bse_float_zap_denormal (register float fval); /* slow */ 00095 static inline double bse_double_zap_denormal (register double dval); /* slow */ 00096 00097 /* --- coarse but fast variants to eliminate denormalized floats --- */ 00098 /* pure arithmetic flushing, fastest with -ffast-math */ 00099 #define BSE_FLOAT_FLUSH(mutable_float) BSE_FLOAT_FLUSH_with_threshold (mutable_float) 00100 #define BSE_DOUBLE_FLUSH(mutable_double) BSE_DOUBLE_FLUSH_with_threshold (mutable_double) 00101 #if 0 /* may be slow in non-inlined functions */ 00102 #define BSE_FLOAT_FLUSH(mutable_float) BSE_FLOAT_FLUSH_with_cond (mutable_float) 00103 #define BSE_DOUBLE_FLUSH(mutable_double) BSE_DOUBLE_FLUSH_with_cond (mutable_double) 00104 #endif 00105 #if 0 /* branching may hurt performance in excessively inlined code */ 00106 #define BSE_FLOAT_FLUSH(mutable_float) BSE_FLOAT_FLUSH_with_if (mutable_float) 00107 #define BSE_DOUBLE_FLUSH(mutable_double) BSE_DOUBLE_FLUSH_with_if (mutable_double) 00108 #endif 00109 00110 /* --- rounding --- */ 00111 typedef unsigned short int BseFpuState; 00112 #if defined (__i386__) && defined (__GNUC__) 00113 /* setting/restoring rounding mode shouldn't actually 00114 * be necessary as round-to-nearest is the hardware 00115 * default (can be checked with bse_fpu_okround()). 00116 */ 00117 static inline void bse_fpu_setround (BseFpuState *cw); 00118 static inline int bse_fpu_okround (void); 00119 static inline void bse_fpu_restore (BseFpuState cv); 00120 static inline int bse_ftoi /* nearest */ (register float f) G_GNUC_CONST; 00121 static inline int bse_dtoi /* nearest */ (register double f) G_GNUC_CONST; 00122 /* fallbacks for the !386 case are below */ 00123 #endif 00124 static inline guint64 bse_dtoull (const double v); 00125 static inline gint64 bse_dtoll (const double v); 00126 00127 /* --- implementation bits --- */ 00128 #if G_BYTE_ORDER == G_LITTLE_ENDIAN 00129 typedef union 00130 { 00131 float v_float; 00132 struct { 00133 uint mantissa : 23; 00134 uint biased_exponent : 8; 00135 uint sign : 1; 00136 } mpn; 00137 } BseFloatIEEE754; 00138 typedef union 00139 { 00140 double v_double; 00141 struct { 00142 uint mantissa_low : 32; 00143 uint mantissa_high : 20; 00144 uint biased_exponent : 11; 00145 uint sign : 1; 00146 } mpn; 00147 } BseDoubleIEEE754; 00148 #define _BSE_DOUBLE_INF_BYTES { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f } 00149 #define _BSE_DOUBLE_NAN_BYTES { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f } 00150 #define _BSE_FLOAT_INF_BYTES { 0x00, 0x00, 0x80, 0x7f } 00151 #define _BSE_FLOAT_NAN_BYTES { 0x00, 0x00, 0xc0, 0x7f } 00152 #elif G_BYTE_ORDER == G_BIG_ENDIAN 00153 typedef union 00154 { 00155 float v_float; 00156 struct { 00157 uint sign : 1; 00158 uint biased_exponent : 8; 00159 uint mantissa : 23; 00160 } mpn; 00161 } BseFloatIEEE754; 00162 typedef union 00163 { 00164 double v_double; 00165 struct { 00166 uint sign : 1; 00167 uint biased_exponent : 11; 00168 uint mantissa_high : 20; 00169 uint mantissa_low : 32; 00170 } mpn; 00171 } BseDoubleIEEE754; 00172 #define _BSE_DOUBLE_INF_BYTES { 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } 00173 #define _BSE_DOUBLE_NAN_BYTES { 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } 00174 #define _BSE_FLOAT_INF_BYTES { 0x7f, 0x80, 0x00, 0x00 } 00175 #define _BSE_FLOAT_NAN_BYTES { 0x7f, 0xc0, 0x00, 0x00 } 00176 #else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */ 00177 #error unknown ENDIAN type 00178 #endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */ 00179 00180 static const union { unsigned char c[8]; double d; } _bse_dnan_union = { _BSE_DOUBLE_NAN_BYTES }; 00181 static const union { unsigned char c[8]; double d; } _bse_dinf_union = { _BSE_DOUBLE_INF_BYTES }; 00182 static const union { unsigned char c[4]; float f; } _bse_fnan_union = { _BSE_FLOAT_NAN_BYTES }; 00183 static const union { unsigned char c[4]; float f; } _bse_finf_union = { _BSE_FLOAT_INF_BYTES }; 00184 00185 /* get structured parts of floating point numbers */ 00186 #if __cplusplus 00187 extern inline BseFloatIEEE754 BSE_FLOAT_PARTS (register float fvalue) { BseFloatIEEE754 fret = { fvalue }; return fret; } 00188 extern inline BseDoubleIEEE754 BSE_DOUBLE_PARTS (register double dvalue) { BseDoubleIEEE754 dret = { dvalue }; return dret; } 00189 #else 00190 #define BSE_FLOAT_PARTS(f) (((BseFloatIEEE754) (f))) 00191 #define BSE_DOUBLE_PARTS(d) (((BseDoubleIEEE754) (d))) 00192 #endif 00193 00194 /* --- implementation details --- */ 00195 static inline float 00196 bse_float_zap_denormal (register float fval) 00197 { 00198 if (G_UNLIKELY (BSE_FLOAT_IS_SUBNORMAL (fval))) 00199 return 0; 00200 else 00201 return fval; 00202 } 00203 00204 static inline double 00205 bse_double_zap_denormal (register double dval) 00206 { 00207 if (G_UNLIKELY (BSE_DOUBLE_IS_SUBNORMAL (dval))) 00208 return 0; 00209 else 00210 return dval; 00211 } 00212 00213 /* use float arithmetic cancellation to eliminate denormals */ 00214 #define BSE_FLOAT_FLUSH_with_threshold(mutable_float) do { \ 00215 volatile float __forced_float = 1e-29 + mutable_float; \ 00216 mutable_float = __forced_float - 1e-29; \ 00217 } while (0) 00218 #define BSE_DOUBLE_FLUSH_with_threshold(mutable_double) do { \ 00219 volatile double __forced_double = 1e-288 + mutable_double; \ 00220 mutable_double = __forced_double - 1e-288; \ 00221 } while (0) 00222 /* substitute with 0 beyond a certain threashold greater than possible denormals */ 00223 #define BSE_FLOAT_FLUSH_with_cond(mutable_float) do { \ 00224 mutable_float = G_UNLIKELY (fabs (mutable_float) < 1e-32) ? 0 : mutable_float; \ 00225 } while (0) 00226 #define BSE_DOUBLE_FLUSH_with_cond(mutable_double) do { \ 00227 mutable_double = G_UNLIKELY (fabs (mutable_double) < 1e-290) ? 0 : mutable_double; \ 00228 } while (0) 00229 /* set everything to 0 beyond a certain threashold greater than possible denormals */ 00230 #define BSE_FLOAT_FLUSH_with_if(mutable_float) do { \ 00231 if (G_UNLIKELY (fabs (mutable_float) < 1e-32)) \ 00232 mutable_float = 0; \ 00233 } while (0) 00234 #define BSE_DOUBLE_FLUSH_with_if(mutable_double) do { \ 00235 if (G_UNLIKELY (fabs (mutable_double) < 1e-290)) \ 00236 mutable_double = 0; \ 00237 } while (0) 00238 00239 #if defined (__i386__) && defined (__GNUC__) 00240 static inline void 00241 bse_fpu_setround (BseFpuState *cw) 00242 { 00243 BseFpuState cv; 00244 00245 __asm__ ("fnstcw %0" 00246 : "=m" (*&cv)); 00247 *cw = cv; 00248 cv &= ~0x0c00; 00249 __asm__ ("fldcw %0" 00250 : 00251 : "m" (*&cv)); 00252 } 00253 static inline int 00254 bse_fpu_okround (void) 00255 { 00256 BseFpuState cv; 00257 00258 __asm__ ("fnstcw %0" 00259 : "=m" (*&cv)); 00260 return !(cv & 0x0c00); 00261 } 00262 static inline void 00263 bse_fpu_restore (BseFpuState cv) 00264 { 00265 __asm__ ("fldcw %0" 00266 : 00267 : "m" (*&cv)); 00268 } 00269 static inline int G_GNUC_CONST 00270 bse_ftoi (register float f) 00271 { 00272 int r; 00273 00274 __asm__ ("fistl %0" 00275 : "=m" (r) 00276 : "t" (f)); 00277 return r; 00278 } 00279 static inline int G_GNUC_CONST 00280 bse_dtoi (register double f) 00281 { 00282 int r; 00283 00284 __asm__ ("fistl %0" 00285 : "=m" (r) 00286 : "t" (f)); 00287 return r; 00288 } 00289 #else /* !386 */ 00290 # define bse_fpu_setround(p) ((void) (p)); 00291 # define bse_fpu_okround() (1) 00292 # define bse_fpu_restore(x) /* nop */ 00293 static inline int G_GNUC_CONST 00294 bse_ftoi (register float v) 00295 { 00296 return (int) (v < -0.0 ? v - 0.5 : v + 0.5); 00297 } 00298 static inline int G_GNUC_CONST 00299 bse_dtoi (register double v) 00300 { 00301 return (int) (v < -0.0 ? v - 0.5 : v + 0.5); 00302 } 00303 #endif 00304 static inline guint64 00305 bse_dtoull (const double v) 00306 { 00307 return v < -0.0 ? (guint64) (v - 0.5) : (guint64) (v + 0.5); 00308 } 00309 static inline gint64 00310 bse_dtoll (const double v) 00311 { 00312 return v < -0.0 ? (gint64) (v - 0.5) : (gint64) (v + 0.5); 00313 } 00314 00315 G_END_DECLS 00316 00317 #endif /* __BSE_IEEE754_H__ */ /* vim: set ts=8 sw=2 sts=2: */