BEAST/BSE - Better Audio System and Sound Engine  0.9.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
bseieee754.hh
Go to the documentation of this file.
1  // Licensed GNU LGPL v2.1 or later: http://www.gnu.org/licenses/lgpl.html
2 #ifndef __BSE_IEEE754_H__
3 #define __BSE_IEEE754_H__
4 
5 #include <bse/bsedefs.hh>
6 #include <math.h> /* signbit */
7 
8 /* override math.h definition of PI */
9 #undef PI
10 #define PI (3.141592653589793238462643383279502884197) // pi
11 
12 G_BEGIN_DECLS
13 
14 /* IEEE 754 single precision floating point layout:
15  * 31 30 23 22 0
16  * +--------+---------------+---------------+
17  * | s 1bit | e[30:23] 8bit | f[22:0] 23bit |
18  * +--------+---------------+---------------+
19  * B0------------------->B1------->B2-->B3-->
20  *
21  * IEEE 754 double precision floating point layout:
22  * 63 62 52 51 32 31 0
23  * +--------+----------------+----------------+ +---------------+
24  * | s 1bit | e[62:52] 11bit | f[51:32] 20bit | | f[31:0] 32bit |
25  * +--------+----------------+----------------+ +---------------+
26  * B0--------------->B1---------->B2--->B3----> B4->B5->B6->B7->
27  */
28 
29 /* floating point type related constants */
30 #define BSE_FLOAT_BIAS (127)
31 #define BSE_FLOAT_MAX_NORMAL (3.40282347e+38) /* 7f7fffff, 2^128 * (1 - BSE_FLOAT_EPSILON) */
32 #define BSE_FLOAT_MIN_NORMAL (1.17549435e-38) /* 00800000 */
33 #define BSE_FLOAT_MAX_SUBNORMAL (1.17549421e-38) /* 007fffff */
34 #define BSE_FLOAT_MIN_SUBNORMAL (1.40129846e-45) /* 00000001 */
35 #define BSE_FLOAT_EPSILON (5.9604644775390625e-08) /* 2^-24, round-off error at 1.0 */
36 #define BSE_DOUBLE_BIAS (1023)
37 #define BSE_DOUBLE_MAX_NORMAL (1.7976931348623157e+308) /* 7fefffff ffffffff, 2^1024 * (1 - BSE_DOUBLE_EPSILON) */
38 #define BSE_DOUBLE_MIN_NORMAL (2.2250738585072014e-308) /* 00100000 00000000 */
39 #define BSE_DOUBLE_MAX_SUBNORMAL (2.2250738585072009e-308) /* 000fffff ffffffff */
40 #define BSE_DOUBLE_MIN_SUBNORMAL (4.9406564584124654e-324) /* 00000000 00000001 */
41 #define BSE_DOUBLE_EPSILON (1.1102230246251565404236316680908203125e-16) /* 2^-53, round-off error at 1.0 */
42 #define BSE_DOUBLE_INF (_bse_dinf_union.d)
43 #define BSE_DOUBLE_NAN (_bse_dnan_union.d)
44 #define BSE_FLOAT_INF (_bse_finf_union.f)
45 #define BSE_FLOAT_NAN (_bse_fnan_union.f)
46 
47 /* multiply with base2 exponent to get base10 exponent (for nomal numbers) */
48 #define BSE_LOG_2_BASE_10 (0.30102999566398119521)
49 
50 /* the following macros work only on variables
51  * and evaluate arguments multiple times
52  */
53 
54 /* single precision value checks */
55 #define BSE_FLOAT_IS_ZERO(f) ((f) == 0.0) /* compiler knows this one */
56 #define BSE_FLOAT_IS_NORMAL(f) (BSE_FLOAT_PARTS (f).mpn.biased_exponent > 0 && \
57  BSE_FLOAT_PARTS (f).mpn.biased_exponent < 255)
58 #define BSE_FLOAT_IS_SUBNORMAL(f) (BSE_FLOAT_PARTS (f).mpn.biased_exponent == 0 && \
59  BSE_FLOAT_PARTS (f).mpn.mantissa != 0)
60 #define BSE_FLOAT_IS_NANINF(f) (BSE_FLOAT_PARTS (f).mpn.biased_exponent == 255)
61 #define BSE_FLOAT_IS_NAN(f) (BSE_FLOAT_IS_NANINF (f) && BSE_FLOAT_PARTS (f).mpn.mantissa != 0)
62 #define BSE_FLOAT_IS_INF(f) (BSE_FLOAT_IS_NANINF (f) && BSE_FLOAT_PARTS (f).mpn.mantissa == 0)
63 #define BSE_FLOAT_IS_INF_POSITIVE(f) (BSE_FLOAT_IS_INF (f) && BSE_FLOAT_PARTS (f).mpn.sign == 0)
64 #define BSE_FLOAT_IS_INF_NEGATIVE(f) (BSE_FLOAT_IS_INF (f) && BSE_FLOAT_PARTS (f).mpn.sign == 1)
65 #ifdef signbit
66 #define BSE_FLOAT_SIGN(f) (signbit (f))
67 #else
68 #define BSE_FLOAT_SIGN(f) (BSE_FLOAT_PARTS (f).mpn.sign)
69 #endif
70 
71 /* double precision value checks */
72 #define BSE_DOUBLE_IS_ZERO(d) ((d) == 0.0) /* compiler knows this one */
73 #define BSE_DOUBLE_IS_NORMAL(d) (BSE_DOUBLE_PARTS (d).mpn.biased_exponent > 0 && \
74  BSE_DOUBLE_PARTS (d).mpn.biased_exponent < 2047)
75 #define BSE_DOUBLE_IS_SUBNORMAL(d) (BSE_DOUBLE_PARTS (d).mpn.biased_exponent == 0 && \
76  (BSE_DOUBLE_PARTS (d).mpn.mantissa_low != 0 || \
77  BSE_DOUBLE_PARTS (d).mpn.mantissa_high != 0))
78 #define BSE_DOUBLE_IS_NANINF(d) (BSE_DOUBLE_PARTS (d).mpn.biased_exponent == 2047)
79 #define BSE_DOUBLE_IS_NAN(d) (BSE_DOUBLE_IS_NANINF (d) && \
80  (BSE_DOUBLE_PARTS (d).mpn.mantissa_low != 0 || \
81  BSE_DOUBLE_PARTS (d).mpn.mantissa_high != 0))
82 #define BSE_DOUBLE_IS_INF(d) (BSE_DOUBLE_IS_NANINF (d) && \
83  BSE_DOUBLE_PARTS (d).mpn.mantissa_low == 0 && \
84  BSE_DOUBLE_PARTS (d).mpn.mantissa_high == 0)
85 #define BSE_DOUBLE_IS_INF_POSITIVE(d) (BSE_DOUBLE_IS_INF (d) && BSE_DOUBLE_PARTS (d).mpn.sign == 0)
86 #define BSE_DOUBLE_IS_INF_NEGATIVE(d) (BSE_DOUBLE_IS_INF (d) && BSE_DOUBLE_PARTS (d).mpn.sign == 1)
87 #ifdef signbit
88 #define BSE_DOUBLE_SIGN(d) (signbit (d))
89 #else
90 #define BSE_DOUBLE_SIGN(d) (BSE_DOUBLE_PARTS (d).mpn.sign)
91 #endif
92 
93 /* --- denormal float handling --- */
94 static inline float bse_float_zap_denormal (register float fval); /* slow */
95 static inline double bse_double_zap_denormal (register double dval); /* slow */
96 
97 /* --- coarse but fast variants to eliminate denormalized floats --- */
98 /* pure arithmetic flushing, fastest with -ffast-math */
99 #define BSE_FLOAT_FLUSH(mutable_float) BSE_FLOAT_FLUSH_with_threshold (mutable_float)
100 #define BSE_DOUBLE_FLUSH(mutable_double) BSE_DOUBLE_FLUSH_with_threshold (mutable_double)
101 #if 0 /* may be slow in non-inlined functions */
102 #define BSE_FLOAT_FLUSH(mutable_float) BSE_FLOAT_FLUSH_with_cond (mutable_float)
103 #define BSE_DOUBLE_FLUSH(mutable_double) BSE_DOUBLE_FLUSH_with_cond (mutable_double)
104 #endif
105 #if 0 /* branching may hurt performance in excessively inlined code */
106 #define BSE_FLOAT_FLUSH(mutable_float) BSE_FLOAT_FLUSH_with_if (mutable_float)
107 #define BSE_DOUBLE_FLUSH(mutable_double) BSE_DOUBLE_FLUSH_with_if (mutable_double)
108 #endif
109 
110 /* --- rounding --- */
111 typedef unsigned short int BseFpuState;
112 #if defined (__i386__) && defined (__GNUC__)
113 /* setting/restoring rounding mode shouldn't actually
114  * be necessary as round-to-nearest is the hardware
115  * default (can be checked with bse_fpu_okround()).
116  */
117 static inline void bse_fpu_setround (BseFpuState *cw);
118 static inline int bse_fpu_okround (void);
119 static inline void bse_fpu_restore (BseFpuState cv);
120 static inline int bse_ftoi /* nearest */ (register float f) G_GNUC_CONST;
121 static inline int bse_dtoi /* nearest */ (register double f) G_GNUC_CONST;
122 /* fallbacks for the !386 case are below */
123 #endif
124 static inline guint64 bse_dtoull (const double v);
125 static inline gint64 bse_dtoll (const double v);
126 
127 /* --- implementation bits --- */
128 #if G_BYTE_ORDER == G_LITTLE_ENDIAN
129 typedef union
130 {
131  float v_float;
132  struct {
133  uint mantissa : 23;
134  uint biased_exponent : 8;
135  uint sign : 1;
136  } mpn;
138 typedef union
139 {
140  double v_double;
141  struct {
142  uint mantissa_low : 32;
143  uint mantissa_high : 20;
144  uint biased_exponent : 11;
145  uint sign : 1;
146  } mpn;
148 #define _BSE_DOUBLE_INF_BYTES { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f }
149 #define _BSE_DOUBLE_NAN_BYTES { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x7f }
150 #define _BSE_FLOAT_INF_BYTES { 0x00, 0x00, 0x80, 0x7f }
151 #define _BSE_FLOAT_NAN_BYTES { 0x00, 0x00, 0xc0, 0x7f }
152 #elif G_BYTE_ORDER == G_BIG_ENDIAN
153 typedef union
154 {
155  float v_float;
156  struct {
157  uint sign : 1;
158  uint biased_exponent : 8;
159  uint mantissa : 23;
160  } mpn;
162 typedef union
163 {
164  double v_double;
165  struct {
166  uint sign : 1;
167  uint biased_exponent : 11;
168  uint mantissa_high : 20;
169  uint mantissa_low : 32;
170  } mpn;
172 #define _BSE_DOUBLE_INF_BYTES { 0x7f, 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
173 #define _BSE_DOUBLE_NAN_BYTES { 0x7f, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
174 #define _BSE_FLOAT_INF_BYTES { 0x7f, 0x80, 0x00, 0x00 }
175 #define _BSE_FLOAT_NAN_BYTES { 0x7f, 0xc0, 0x00, 0x00 }
176 #else /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
177 #error unknown ENDIAN type
178 #endif /* !G_LITTLE_ENDIAN && !G_BIG_ENDIAN */
179 
180 static const union { unsigned char c[8]; double d; } _bse_dnan_union = { _BSE_DOUBLE_NAN_BYTES };
181 static const union { unsigned char c[8]; double d; } _bse_dinf_union = { _BSE_DOUBLE_INF_BYTES };
182 static const union { unsigned char c[4]; float f; } _bse_fnan_union = { _BSE_FLOAT_NAN_BYTES };
183 static const union { unsigned char c[4]; float f; } _bse_finf_union = { _BSE_FLOAT_INF_BYTES };
184 
185 /* get structured parts of floating point numbers */
186 #if __cplusplus
187 extern inline BseFloatIEEE754 BSE_FLOAT_PARTS (register float fvalue) { BseFloatIEEE754 fret = { fvalue }; return fret; }
188 extern inline BseDoubleIEEE754 BSE_DOUBLE_PARTS (register double dvalue) { BseDoubleIEEE754 dret = { dvalue }; return dret; }
189 #else
190 #define BSE_FLOAT_PARTS(f) (((BseFloatIEEE754) (f)))
191 #define BSE_DOUBLE_PARTS(d) (((BseDoubleIEEE754) (d)))
192 #endif
193 
194 /* --- implementation details --- */
195 static inline float
196 bse_float_zap_denormal (register float fval)
197 {
198  if (G_UNLIKELY (BSE_FLOAT_IS_SUBNORMAL (fval)))
199  return 0;
200  else
201  return fval;
202 }
203 
204 static inline double
205 bse_double_zap_denormal (register double dval)
206 {
207  if (G_UNLIKELY (BSE_DOUBLE_IS_SUBNORMAL (dval)))
208  return 0;
209  else
210  return dval;
211 }
212 
213 /* use float arithmetic cancellation to eliminate denormals */
214 #define BSE_FLOAT_FLUSH_with_threshold(mutable_float) do { \
215  volatile float __forced_float = 1e-29 + mutable_float; \
216  mutable_float = __forced_float - 1e-29; \
217 } while (0)
218 #define BSE_DOUBLE_FLUSH_with_threshold(mutable_double) do { \
219  volatile double __forced_double = 1e-288 + mutable_double; \
220  mutable_double = __forced_double - 1e-288; \
221 } while (0)
222 /* substitute with 0 beyond a certain threashold greater than possible denormals */
223 #define BSE_FLOAT_FLUSH_with_cond(mutable_float) do { \
224  mutable_float = G_UNLIKELY (fabs (mutable_float) < 1e-32) ? 0 : mutable_float; \
225 } while (0)
226 #define BSE_DOUBLE_FLUSH_with_cond(mutable_double) do { \
227  mutable_double = G_UNLIKELY (fabs (mutable_double) < 1e-290) ? 0 : mutable_double; \
228 } while (0)
229 /* set everything to 0 beyond a certain threashold greater than possible denormals */
230 #define BSE_FLOAT_FLUSH_with_if(mutable_float) do { \
231  if (G_UNLIKELY (fabs (mutable_float) < 1e-32)) \
232  mutable_float = 0; \
233 } while (0)
234 #define BSE_DOUBLE_FLUSH_with_if(mutable_double) do { \
235  if (G_UNLIKELY (fabs (mutable_double) < 1e-290)) \
236  mutable_double = 0; \
237 } while (0)
238 
239 #if defined (__i386__) && defined (__GNUC__)
240 static inline void
241 bse_fpu_setround (BseFpuState *cw)
242 {
243  BseFpuState cv;
244 
245  __asm__ ("fnstcw %0"
246  : "=m" (*&cv));
247  *cw = cv;
248  cv &= ~0x0c00;
249  __asm__ ("fldcw %0"
250  :
251  : "m" (*&cv));
252 }
253 static inline int
254 bse_fpu_okround (void)
255 {
256  BseFpuState cv;
257 
258  __asm__ ("fnstcw %0"
259  : "=m" (*&cv));
260  return !(cv & 0x0c00);
261 }
262 static inline void
263 bse_fpu_restore (BseFpuState cv)
264 {
265  __asm__ ("fldcw %0"
266  :
267  : "m" (*&cv));
268 }
269 static inline int G_GNUC_CONST
270 bse_ftoi (register float f)
271 {
272  int r;
273 
274  __asm__ ("fistl %0"
275  : "=m" (r)
276  : "t" (f));
277  return r;
278 }
279 static inline int G_GNUC_CONST
280 bse_dtoi (register double f)
281 {
282  int r;
283 
284  __asm__ ("fistl %0"
285  : "=m" (r)
286  : "t" (f));
287  return r;
288 }
289 #else /* !386 */
290 # define bse_fpu_setround(p) ((void) (p));
291 # define bse_fpu_okround() (1)
292 # define bse_fpu_restore(x) /* nop */
293 static inline int G_GNUC_CONST
294 bse_ftoi (register float v)
295 {
296  return (int) (v < -0.0 ? v - 0.5 : v + 0.5);
297 }
298 static inline int G_GNUC_CONST
299 bse_dtoi (register double v)
300 {
301  return (int) (v < -0.0 ? v - 0.5 : v + 0.5);
302 }
303 #endif
304 static inline guint64
305 bse_dtoull (const double v)
306 {
307  return v < -0.0 ? (guint64) (v - 0.5) : (guint64) (v + 0.5);
308 }
309 static inline gint64
310 bse_dtoll (const double v)
311 {
312  return v < -0.0 ? (gint64) (v - 0.5) : (gint64) (v + 0.5);
313 }
314 
315 G_END_DECLS
316 
317 #endif /* __BSE_IEEE754_H__ */ /* vim: set ts=8 sw=2 sts=2: */
Definition: bseieee754.hh:138
Definition: bseieee754.hh:129