Merge branch 'master' of http://www-dev.cockos.com/wdl/WDL into updatewdl
[wdl/wdl-ol.git] / WDL / denormal.h
blobbf29a12be058ef6182d9d7ddbbe1bf150d641aca
1 #ifndef _WDL_DENORMAL_H_
2 #define _WDL_DENORMAL_H_
4 typedef struct
5 {
6 #ifdef __ppc__ // todo: other big endian platforms...
7 unsigned int hw;
8 unsigned int lw;
9 #else
10 unsigned int lw;
11 unsigned int hw;
12 #endif
13 } WDL_DenormalTwoInts;
15 typedef union { double fl; WDL_DenormalTwoInts w; } WDL_DenormalDoubleAccess;
16 typedef union { float fl; unsigned int w; } WDL_DenormalFloatAccess;
19 // note: the _aggressive versions filter out anything less than around 1.0e-16 or so (approximately) to 0.0, including -0.0 (becomes 0.0)
20 // note: new! the _aggressive versions also filter inf and NaN to 0.0
22 #ifdef __cplusplus
23 #define WDL_DENORMAL_INLINE inline
24 #elif defined(_MSC_VER)
25 #define WDL_DENORMAL_INLINE __inline
26 #else
27 #define WDL_DENORMAL_INLINE
28 #endif
30 #define WDL_DENORMAL_DOUBLE_HW(a) (((const WDL_DenormalDoubleAccess*)(a))->w.hw)
31 #define WDL_DENORMAL_DOUBLE_LW(a) (((const WDL_DenormalDoubleAccess*)(a))->w.lw)
32 #define WDL_DENORMAL_FLOAT_W(a) (((const WDL_DenormalFloatAccess*)(a))->w)
34 #define WDL_DENORMAL_DOUBLE_HW_NC(a) (((WDL_DenormalDoubleAccess*)(a))->w.hw)
35 #define WDL_DENORMAL_DOUBLE_LW_NC(a) (((WDL_DenormalDoubleAccess*)(a))->w.lw)
36 #define WDL_DENORMAL_FLOAT_W_NC(a) (((WDL_DenormalFloatAccess*)(a))->w)
38 #define WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF 0x3cA00000 // 0x3B8000000 maybe instead? that's 10^-5 smaller or so
39 #define WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF 0x25000000
41 #define WDL_NOT_DENORMAL_DOUBLE(a) (WDL_DENORMAL_DOUBLE_HW(a)&0x7ff00000)
42 #define WDL_NOT_DENORMAL_FLOAT(a) (WDL_DENORMAL_FLOAT_W(a)&0x7f800000)
44 #define WDL_DENORMAL_OR_ZERO_DOUBLE(a) (!WDL_NOT_DENORMAL_DOUBLE(a))
45 #define WDL_DENORMAL_OR_ZERO_FLOAT(a) (!WDL_NOT_DENORMAL_FLOAT(a))
46 #define WDL_DENORMAL_OR_ZERO_DOUBLE_AGGRESSIVE(a) (((WDL_DENORMAL_DOUBLE_HW(a)+0x100000)&0x7ff00000) < WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF)
47 #define WDL_DENORMAL_OR_ZERO_FLOAT_AGGRESSIVE(a) (((WDL_DENORMAL_FLOAT_W(a)+0x800000)&0x7f800000) < WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF)
49 static double WDL_DENORMAL_INLINE denormal_filter_double(double a)
51 return (WDL_DENORMAL_DOUBLE_HW(&a)&0x7ff00000) ? a : 0.0;
54 static double WDL_DENORMAL_INLINE denormal_filter_double2(double a)
56 return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) > 0x100000 ? a : 0.0;
59 static double WDL_DENORMAL_INLINE denormal_filter_double_aggressive(double a)
61 return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) >= WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF ? a : 0.0;
64 static float WDL_DENORMAL_INLINE denormal_filter_float(float a)
66 return (WDL_DENORMAL_FLOAT_W(&a)&0x7f800000) ? a : 0.0f;
69 static float WDL_DENORMAL_INLINE denormal_filter_float2(float a)
71 return ((WDL_DENORMAL_FLOAT_W(&a)+0x800000)&0x7f800000) > 0x800000 ? a : 0.0f;
75 static float WDL_DENORMAL_INLINE denormal_filter_float_aggressive(float a)
77 return ((WDL_DENORMAL_FLOAT_W(&a)+0x800000)&0x7f800000) >= WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF ? a : 0.0f;
79 static void WDL_DENORMAL_INLINE denormal_fix_double(double *a)
81 if (!(WDL_DENORMAL_DOUBLE_HW(a)&0x7ff00000)) *a=0.0;
84 static void WDL_DENORMAL_INLINE denormal_fix_double_aggressive(double *a)
86 if (((WDL_DENORMAL_DOUBLE_HW(a)+0x100000)&0x7ff00000) < WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF) *a=0.0;
89 static void WDL_DENORMAL_INLINE denormal_fix_float(float *a)
91 if (!(WDL_DENORMAL_FLOAT_W(a)&0x7f800000)) *a=0.0f;
93 static void WDL_DENORMAL_INLINE denormal_fix_float_aggressive(float *a)
95 if (((WDL_DENORMAL_FLOAT_W(a)+0x800000)&0x7f800000) < WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF) *a=0.0f;
100 #ifdef __cplusplus // automatic typed versions (though one should probably use the explicit versions...
103 static double WDL_DENORMAL_INLINE denormal_filter(double a)
105 return (WDL_DENORMAL_DOUBLE_HW(&a)&0x7ff00000) ? a : 0.0;
107 static double WDL_DENORMAL_INLINE denormal_filter_aggressive(double a)
109 return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) >= WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF ? a : 0.0;
112 static float WDL_DENORMAL_INLINE denormal_filter(float a)
114 return (WDL_DENORMAL_FLOAT_W(&a)&0x7f800000) ? a : 0.0f;
117 static float WDL_DENORMAL_INLINE denormal_filter_aggressive(float a)
119 return ((WDL_DENORMAL_FLOAT_W(&a)+0x800000)&0x7f800000) >= WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF ? a : 0.0f;
122 static void WDL_DENORMAL_INLINE denormal_fix(double *a)
124 if (!(WDL_DENORMAL_DOUBLE_HW(a)&0x7ff00000)) *a=0.0;
126 static void WDL_DENORMAL_INLINE denormal_fix_aggressive(double *a)
128 if (((WDL_DENORMAL_DOUBLE_HW(a)+0x100000)&0x7ff00000) < WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF) *a=0.0;
130 static void WDL_DENORMAL_INLINE denormal_fix(float *a)
132 if (!(WDL_DENORMAL_FLOAT_W(a)&0x7f800000)) *a=0.0f;
134 static void WDL_DENORMAL_INLINE denormal_fix_aggressive(float *a)
136 if (((WDL_DENORMAL_FLOAT_W(a)+0x800000)&0x7f800000) < WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF) *a=0.0f;
139 static bool WDL_DENORMAL_INLINE WDL_DENORMAL_OR_ZERO(double *a)
141 return WDL_DENORMAL_OR_ZERO_DOUBLE(a);
144 static bool WDL_DENORMAL_INLINE WDL_DENORMAL_OR_ZERO(float *a)
146 return WDL_DENORMAL_OR_ZERO_FLOAT(a);
149 static bool WDL_DENORMAL_INLINE WDL_DENORMAL_OR_ZERO_AGGRESSIVE(double *a)
151 return WDL_DENORMAL_OR_ZERO_DOUBLE_AGGRESSIVE(a);
154 static bool WDL_DENORMAL_INLINE WDL_DENORMAL_OR_ZERO_AGGRESSIVE(float *a)
156 return WDL_DENORMAL_OR_ZERO_FLOAT_AGGRESSIVE(a);
161 #endif // cplusplus versions
166 ////////////////////
167 // this isnt a denormal function but it is similar, so we'll put it here as a bonus
169 static void WDL_DENORMAL_INLINE GetDoubleMaxAbsValue(double *out, const double *in) // note: the value pointed to by "out" must be >=0.0, __NOT__ <= -0.0
171 unsigned int hw = WDL_DENORMAL_DOUBLE_HW(in)&0x7fffffff;
172 if (hw >= WDL_DENORMAL_DOUBLE_HW(out) && (hw>WDL_DENORMAL_DOUBLE_HW(out) || WDL_DENORMAL_DOUBLE_LW(in) > WDL_DENORMAL_DOUBLE_LW(out)))
174 WDL_DENORMAL_DOUBLE_LW_NC(out) = WDL_DENORMAL_DOUBLE_LW(in);
175 WDL_DENORMAL_DOUBLE_HW_NC(out) = hw;
179 static void WDL_DENORMAL_INLINE GetFloatMaxAbsValue(float *out, const float *in) // note: the value pointed to by "out" must be >=0.0, __NOT__ <= -0.0
181 unsigned int hw = WDL_DENORMAL_FLOAT_W(in)&0x7fffffff;
182 if (hw > WDL_DENORMAL_FLOAT_W(out)) WDL_DENORMAL_FLOAT_W_NC(out)=hw;
186 #ifdef __cplusplus
187 static void WDL_DENORMAL_INLINE GetFloatMaxAbsValue(double *out, const double *in) // note: the value pointed to by "out" must be >=0.0, __NOT__ <= -0.0
189 GetDoubleMaxAbsValue(out,in);
191 #endif
193 #endif