fp_bits.h 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. #pragma once
  2. #include <util/system/defaults.h>
  3. #include <cmath>
  4. #include <limits>
  5. namespace NYql {
  6. /*
  7. double
  8. visual c++
  9. fff8000000000000 0.0/0.0
  10. 7ff8000000000001 snan
  11. 7ff8000000000000 qnan
  12. gcc/clang
  13. 7ff8000000000000 0.0/0.0
  14. 7ff4000000000000 snan
  15. 7ff8000000000000 qnan
  16. float
  17. visual c++
  18. ffc00000 0.0f/0.0f
  19. 7fc00001 snan
  20. 7fc00000 qnan
  21. gcc/clang
  22. 7fc00000 0.0f/0.0f
  23. 7fa00000 snan
  24. 7fc00000 qnan
  25. */
  26. template <typename T>
  27. struct TFpTraits {
  28. static constexpr bool Supported = false;
  29. };
  30. template <>
  31. struct TFpTraits<float> {
  32. static constexpr bool Supported = std::numeric_limits<float>::is_iec559;
  33. using TIntegral = ui32;
  34. static constexpr TIntegral SignMask = (1u << 31);
  35. static constexpr TIntegral Mantissa = 23;
  36. static constexpr TIntegral Exp = 8;
  37. static constexpr TIntegral MaxMantissa = (1u << Mantissa) - 1;
  38. static constexpr TIntegral MaxExp = (1u << Exp) - 1;
  39. static constexpr TIntegral QNan = 0x7fc00000u;
  40. };
  41. template <>
  42. struct TFpTraits<double> {
  43. static constexpr bool Supported = std::numeric_limits<double>::is_iec559;
  44. using TIntegral = ui64;
  45. static constexpr TIntegral SignMask = (1ull << 63);
  46. static constexpr TIntegral Mantissa = 52;
  47. static constexpr TIntegral Exp = 11;
  48. static constexpr TIntegral MaxMantissa = (1ull << Mantissa) - 1;
  49. static constexpr TIntegral MaxExp = (1ull << Exp) - 1;
  50. static constexpr TIntegral QNan = 0x7ff8000000000000ull;
  51. };
  52. template <typename T, bool>
  53. struct TCanonizeFpBitsImpl {
  54. };
  55. template <typename T>
  56. struct TCanonizeFpBitsImpl<T, true> {
  57. static void Do(void* buffer) {
  58. using TTraits = TFpTraits<T>;
  59. using TIntegral = typename TTraits::TIntegral;
  60. const TIntegral value = *(TIntegral*)(buffer);
  61. if (value == TTraits::SignMask) {
  62. *(TIntegral*)buffer = 0;
  63. return;
  64. }
  65. const TIntegral exp = (value >> TTraits::Mantissa) & TTraits::MaxExp;
  66. // inf or nan
  67. if (exp == TTraits::MaxExp) {
  68. if (value & TTraits::MaxMantissa) {
  69. // quiet nan
  70. *(TIntegral*)buffer = TTraits::QNan;
  71. }
  72. }
  73. }
  74. };
  75. template <typename T>
  76. struct TCanonizeFpBitsImpl<T, false> {
  77. static void Do(void* buffer) {
  78. using TNumTraits = std::numeric_limits<T>;
  79. const T value = *(T*)buffer;
  80. switch (std::fpclassify(value)) {
  81. case FP_NAN:
  82. static_assert(TNumTraits::has_quiet_NaN, "no QNAN");
  83. *(T*)buffer = TNumTraits::quiet_NaN();
  84. break;
  85. case FP_ZERO:
  86. *(T*)buffer = T(0);
  87. break;
  88. }
  89. }
  90. };
  91. /*
  92. Canonize floating point number bits.
  93. Converts minus zero to zero and all NaNs to quiet NaN.
  94. @param buffer[in/out] - aligned buffer with floating point number
  95. */
  96. template <typename T>
  97. void CanonizeFpBits(void* buffer) {
  98. return TCanonizeFpBitsImpl<T, TFpTraits<T>::Supported>::Do(buffer);
  99. }
  100. }