BEAST/BSE - Better Audio System and Sound Engine  0.8.2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
bseieee754.hh
Go to the documentation of this file.
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: */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines