#pragma once #include #include #include namespace NYql { /* double visual c++ fff8000000000000 0.0/0.0 7ff8000000000001 snan 7ff8000000000000 qnan gcc/clang 7ff8000000000000 0.0/0.0 7ff4000000000000 snan 7ff8000000000000 qnan float visual c++ ffc00000 0.0f/0.0f 7fc00001 snan 7fc00000 qnan gcc/clang 7fc00000 0.0f/0.0f 7fa00000 snan 7fc00000 qnan */ template struct TFpTraits { static constexpr bool Supported = false; }; template <> struct TFpTraits { static constexpr bool Supported = std::numeric_limits::is_iec559; using TIntegral = ui32; static constexpr TIntegral SignMask = (1u << 31); static constexpr TIntegral Mantissa = 23; static constexpr TIntegral Exp = 8; static constexpr TIntegral MaxMantissa = (1u << Mantissa) - 1; static constexpr TIntegral MaxExp = (1u << Exp) - 1; static constexpr TIntegral QNan = 0x7fc00000u; }; template <> struct TFpTraits { static constexpr bool Supported = std::numeric_limits::is_iec559; using TIntegral = ui64; static constexpr TIntegral SignMask = (1ull << 63); static constexpr TIntegral Mantissa = 52; static constexpr TIntegral Exp = 11; static constexpr TIntegral MaxMantissa = (1ull << Mantissa) - 1; static constexpr TIntegral MaxExp = (1ull << Exp) - 1; static constexpr TIntegral QNan = 0x7ff8000000000000ull; }; template struct TCanonizeFpBitsImpl { }; template struct TCanonizeFpBitsImpl { static void Do(void* buffer) { using TTraits = TFpTraits; using TIntegral = typename TTraits::TIntegral; const TIntegral value = *(TIntegral*)(buffer); if (value == TTraits::SignMask) { *(TIntegral*)buffer = 0; return; } const TIntegral exp = (value >> TTraits::Mantissa) & TTraits::MaxExp; // inf or nan if (exp == TTraits::MaxExp) { if (value & TTraits::MaxMantissa) { // quiet nan *(TIntegral*)buffer = TTraits::QNan; } } } }; template struct TCanonizeFpBitsImpl { static void Do(void* buffer) { using TNumTraits = std::numeric_limits; const T value = *(T*)buffer; switch (std::fpclassify(value)) { case FP_NAN: static_assert(TNumTraits::has_quiet_NaN, "no QNAN"); *(T*)buffer = TNumTraits::quiet_NaN(); break; case FP_ZERO: *(T*)buffer = T(0); break; } } }; /* Canonize floating point number bits. Converts minus zero to zero and all NaNs to quiet NaN. @param buffer[in/out] - aligned buffer with floating point number */ template void CanonizeFpBits(void* buffer) { return TCanonizeFpBitsImpl::Supported>::Do(buffer); } }