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