mxlib
c++ tools for analyzing astronomical data and other tasks by Jared R. Males. [git repo]
Loading...
Searching...
No Matches
floatUtils.hpp
Go to the documentation of this file.
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
15namespace mx
16{
17namespace math
18{
19
20namespace floatUtils_detail
21{
22
23/// Convert an extended floating-point value to a classifiable double without overflowing finite values.
24template <typename realT>
25double normalizedDouble( realT value /**< [in] floating-point value to normalize */ )
26{
27 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 */
38template <typename realT>
39bool 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 constexpr std::uint32_t exponentMask = 0x7f800000U;
46 constexpr std::uint32_t mantissaMask = 0x007fffffU;
47 const std::uint32_t bits = std::bit_cast<std::uint32_t>( value );
48 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 constexpr std::uint64_t exponentMask = 0x7ff0000000000000ULL;
53 constexpr std::uint64_t mantissaMask = 0x000fffffffffffffULL;
54 const std::uint64_t bits = std::bit_cast<std::uint64_t>( value );
55 return ( bits & exponentMask ) == exponentMask && ( bits & mantissaMask ) != 0;
56 }
57 else
58 {
59 const double normalized = floatUtils_detail::normalizedDouble( value );
60 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 */
70template <typename realT>
71bool 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 constexpr std::uint32_t exponentMask = 0x7f800000U;
78 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 constexpr std::uint64_t exponentMask = 0x7ff0000000000000ULL;
83 return ( std::bit_cast<std::uint64_t>( value ) & exponentMask ) != exponentMask;
84 }
85 else
86 {
87 const double normalized = floatUtils_detail::normalizedDouble( value );
88 return isFinite( normalized );
89 }
90}
91
92} // namespace math
93} // namespace mx
94
95#endif // math_floatUtils_hpp
double normalizedDouble(realT value)
Convert an extended floating-point value to a classifiable double without overflowing finite values.
bool isNan(realT value)
Test whether a floating-point value is NaN, including under finite-math-only optimization.
bool isFinite(realT value)
Test whether a floating-point value is finite, including under finite-math-only optimization.
The mxlib c++ namespace.
Definition mxlib.hpp:37