LCOV - code coverage report
Current view: top level - include/math - floatUtils.hpp (source / functions) Coverage Total Hit
Test: mxlib Lines: 100.0 % 20 20
Test Date: 2026-08-30 22:23:37 Functions: 100.0 % 3 3

            Line data    Source code
       1              : /** \file floatUtils.hpp
       2              :  * \author Jared R. Males
       3              :  * \brief Floating-point classification utilities that remain reliable under fast-math optimization.
       4              :  * \ingroup gen_math_files
       5              :  */
       6              : 
       7              : #ifndef math_floatUtils_hpp
       8              : #define math_floatUtils_hpp
       9              : 
      10              : #include <bit>
      11              : #include <cstdint>
      12              : #include <limits>
      13              : #include <type_traits>
      14              : 
      15              : namespace mx
      16              : {
      17              : namespace math
      18              : {
      19              : 
      20              : namespace floatUtils_detail
      21              : {
      22              : 
      23              : /// Convert an extended floating-point value to a classifiable double without overflowing finite values.
      24              : template <typename realT>
      25            4 : double normalizedDouble( realT value /**< [in] floating-point value to normalize */ )
      26              : {
      27            4 :     return static_cast<double>( value / std::numeric_limits<realT>::max() );
      28              : }
      29              : 
      30              : } // namespace floatUtils_detail
      31              : 
      32              : /// Test whether a floating-point value is NaN, including under finite-math-only optimization.
      33              : /**
      34              :  * \returns true if value is a quiet or signaling NaN, otherwise false.
      35              :  *
      36              :  * \ingroup gen_math
      37              :  */
      38              : template <typename realT>
      39           15 : bool isNan( realT value /**< [in] floating-point value to test */ )
      40              : {
      41              :     static_assert( std::is_floating_point_v<realT>, "isNan requires a floating-point type" );
      42              : 
      43              :     if constexpr( std::numeric_limits<realT>::is_iec559 && sizeof( realT ) == sizeof( std::uint32_t ) )
      44              :     {
      45            3 :         constexpr std::uint32_t exponentMask = 0x7f800000U;
      46            3 :         constexpr std::uint32_t mantissaMask = 0x007fffffU;
      47            3 :         const std::uint32_t bits = std::bit_cast<std::uint32_t>( value );
      48            3 :         return ( bits & exponentMask ) == exponentMask && ( bits & mantissaMask ) != 0;
      49              :     }
      50              :     else if constexpr( std::numeric_limits<realT>::is_iec559 && sizeof( realT ) == sizeof( std::uint64_t ) )
      51              :     {
      52           10 :         constexpr std::uint64_t exponentMask = 0x7ff0000000000000ULL;
      53           10 :         constexpr std::uint64_t mantissaMask = 0x000fffffffffffffULL;
      54           10 :         const std::uint64_t bits = std::bit_cast<std::uint64_t>( value );
      55           10 :         return ( bits & exponentMask ) == exponentMask && ( bits & mantissaMask ) != 0;
      56              :     }
      57              :     else
      58              :     {
      59            2 :         const double normalized = floatUtils_detail::normalizedDouble( value );
      60            2 :         return isNan( normalized );
      61              :     }
      62              : }
      63              : 
      64              : /// Test whether a floating-point value is finite, including under finite-math-only optimization.
      65              : /**
      66              :  * \returns true if value is neither infinite nor NaN, otherwise false.
      67              :  *
      68              :  * \ingroup gen_math
      69              :  */
      70              : template <typename realT>
      71        33540 : bool isFinite( realT value /**< [in] floating-point value to test */ )
      72              : {
      73              :     static_assert( std::is_floating_point_v<realT>, "isFinite requires a floating-point type" );
      74              : 
      75              :     if constexpr( std::numeric_limits<realT>::is_iec559 && sizeof( realT ) == sizeof( std::uint32_t ) )
      76              :     {
      77         1547 :         constexpr std::uint32_t exponentMask = 0x7f800000U;
      78         1547 :         return ( std::bit_cast<std::uint32_t>( value ) & exponentMask ) != exponentMask;
      79              :     }
      80              :     else if constexpr( std::numeric_limits<realT>::is_iec559 && sizeof( realT ) == sizeof( std::uint64_t ) )
      81              :     {
      82        31991 :         constexpr std::uint64_t exponentMask = 0x7ff0000000000000ULL;
      83        31991 :         return ( std::bit_cast<std::uint64_t>( value ) & exponentMask ) != exponentMask;
      84              :     }
      85              :     else
      86              :     {
      87            2 :         const double normalized = floatUtils_detail::normalizedDouble( value );
      88            2 :         return isFinite( normalized );
      89              :     }
      90              : }
      91              : 
      92              : } // namespace math
      93              : } // namespace mx
      94              : 
      95              : #endif // math_floatUtils_hpp
        

Generated by: LCOV version 2.0-1