You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

167 lines
5.3KB

  1. #ifndef _WDL_DENORMAL_H_
  2. #define _WDL_DENORMAL_H_
  3. typedef struct
  4. {
  5. #ifdef __ppc__ // todo: other big endian platforms...
  6. unsigned int hw;
  7. unsigned int lw;
  8. #else
  9. unsigned int lw;
  10. unsigned int hw;
  11. #endif
  12. } WDL_DenormalTwoInts;
  13. typedef union { double fl; WDL_DenormalTwoInts w; } WDL_DenormalDoubleAccess;
  14. typedef union { float fl; unsigned int w; } WDL_DenormalFloatAccess;
  15. // 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)
  16. // note: new! the _aggressive versions also filter inf and NaN to 0.0
  17. #ifdef __cplusplus
  18. #define WDL_DENORMAL_INLINE inline
  19. #elif defined(_MSC_VER)
  20. #define WDL_DENORMAL_INLINE __inline
  21. #else
  22. #define WDL_DENORMAL_INLINE
  23. #endif
  24. #define WDL_DENORMAL_DOUBLE_HW(a) (((const WDL_DenormalDoubleAccess*)(a))->w.hw)
  25. #define WDL_DENORMAL_DOUBLE_LW(a) (((const WDL_DenormalDoubleAccess*)(a))->w.lw)
  26. #define WDL_DENORMAL_FLOAT_W(a) (((const WDL_DenormalFloatAccess*)(a))->w)
  27. #define WDL_DENORMAL_DOUBLE_HW_NC(a) (((WDL_DenormalDoubleAccess*)(a))->w.hw)
  28. #define WDL_DENORMAL_DOUBLE_LW_NC(a) (((WDL_DenormalDoubleAccess*)(a))->w.lw)
  29. #define WDL_DENORMAL_FLOAT_W_NC(a) (((WDL_DenormalFloatAccess*)(a))->w)
  30. #define WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF 0x3cA00000 // 0x3B8000000 maybe instead? that's 10^-5 smaller or so
  31. #define WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF 0x25000000
  32. static double WDL_DENORMAL_INLINE denormal_filter_double(double a)
  33. {
  34. return (WDL_DENORMAL_DOUBLE_HW(&a)&0x7ff00000) ? a : 0.0;
  35. }
  36. static double WDL_DENORMAL_INLINE denormal_filter_double2(double a)
  37. {
  38. return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) > 0x100000 ? a : 0.0;
  39. }
  40. static double WDL_DENORMAL_INLINE denormal_filter_double_aggressive(double a)
  41. {
  42. return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) >= WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF ? a : 0.0;
  43. }
  44. static float WDL_DENORMAL_INLINE denormal_filter_float(float a)
  45. {
  46. return (WDL_DENORMAL_FLOAT_W(&a)&0x7f800000) ? a : 0.0f;
  47. }
  48. static float WDL_DENORMAL_INLINE denormal_filter_float2(float a)
  49. {
  50. return ((WDL_DENORMAL_FLOAT_W(&a)+0x800000)&0x7f800000) > 0x800000 ? a : 0.0f;
  51. }
  52. static float WDL_DENORMAL_INLINE denormal_filter_float_aggressive(float a)
  53. {
  54. return ((WDL_DENORMAL_FLOAT_W(&a)+0x800000)&0x7f800000) >= WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF ? a : 0.0f;
  55. }
  56. static void WDL_DENORMAL_INLINE denormal_fix_double(double *a)
  57. {
  58. if (!(WDL_DENORMAL_DOUBLE_HW(a)&0x7ff00000)) *a=0.0;
  59. }
  60. static void WDL_DENORMAL_INLINE denormal_fix_double_aggressive(double *a)
  61. {
  62. if (((WDL_DENORMAL_DOUBLE_HW(a)+0x100000)&0x7ff00000) < WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF) *a=0.0;
  63. }
  64. static void WDL_DENORMAL_INLINE denormal_fix_float(float *a)
  65. {
  66. if (!(WDL_DENORMAL_FLOAT_W(a)&0x7f800000)) *a=0.0f;
  67. }
  68. static void WDL_DENORMAL_INLINE denormal_fix_float_aggressive(float *a)
  69. {
  70. if (((WDL_DENORMAL_FLOAT_W(a)+0x800000)&0x7f800000) < WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF) *a=0.0f;
  71. }
  72. #ifdef __cplusplus // automatic typed versions (though one should probably use the explicit versions...
  73. static double WDL_DENORMAL_INLINE denormal_filter(double a)
  74. {
  75. return (WDL_DENORMAL_DOUBLE_HW(&a)&0x7ff00000) ? a : 0.0;
  76. }
  77. static double WDL_DENORMAL_INLINE denormal_filter_aggressive(double a)
  78. {
  79. return ((WDL_DENORMAL_DOUBLE_HW(&a)+0x100000)&0x7ff00000) >= WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF ? a : 0.0;
  80. }
  81. static float WDL_DENORMAL_INLINE denormal_filter(float a)
  82. {
  83. return (WDL_DENORMAL_FLOAT_W(&a)&0x7f800000) ? a : 0.0f;
  84. }
  85. static float WDL_DENORMAL_INLINE denormal_filter_aggressive(float a)
  86. {
  87. return ((WDL_DENORMAL_FLOAT_W(&a)+0x800000)&0x7f800000) >= WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF ? a : 0.0f;
  88. }
  89. static void WDL_DENORMAL_INLINE denormal_fix(double *a)
  90. {
  91. if (!(WDL_DENORMAL_DOUBLE_HW(a)&0x7ff00000)) *a=0.0;
  92. }
  93. static void WDL_DENORMAL_INLINE denormal_fix_aggressive(double *a)
  94. {
  95. if (((WDL_DENORMAL_DOUBLE_HW(a)+0x100000)&0x7ff00000) < WDL_DENORMAL_DOUBLE_AGGRESSIVE_CUTOFF) *a=0.0;
  96. }
  97. static void WDL_DENORMAL_INLINE denormal_fix(float *a)
  98. {
  99. if (!(WDL_DENORMAL_FLOAT_W(a)&0x7f800000)) *a=0.0f;
  100. }
  101. static void WDL_DENORMAL_INLINE denormal_fix_aggressive(float *a)
  102. {
  103. if (((WDL_DENORMAL_FLOAT_W(a)+0x800000)&0x7f800000) < WDL_DENORMAL_FLOAT_AGGRESSIVE_CUTOFF) *a=0.0f;
  104. }
  105. #endif // cplusplus versions
  106. ////////////////////
  107. // this isnt a denormal function but it is similar, so we'll put it here as a bonus
  108. 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
  109. {
  110. unsigned int hw = WDL_DENORMAL_DOUBLE_HW(in)&0x7fffffff;
  111. if (hw >= WDL_DENORMAL_DOUBLE_HW(out) && (hw>WDL_DENORMAL_DOUBLE_HW(out) || WDL_DENORMAL_DOUBLE_LW(in) > WDL_DENORMAL_DOUBLE_LW(out)))
  112. {
  113. WDL_DENORMAL_DOUBLE_LW_NC(out) = WDL_DENORMAL_DOUBLE_LW(in);
  114. WDL_DENORMAL_DOUBLE_HW_NC(out) = hw;
  115. }
  116. }
  117. 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
  118. {
  119. unsigned int hw = WDL_DENORMAL_FLOAT_W(in)&0x7fffffff;
  120. if (hw > WDL_DENORMAL_FLOAT_W(out)) WDL_DENORMAL_FLOAT_W_NC(out)=hw;
  121. }
  122. #ifdef __cplusplus
  123. 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
  124. {
  125. GetDoubleMaxAbsValue(out,in);
  126. }
  127. #endif
  128. #endif