LCOV - code coverage report
Current view: top level - port - cpl_float.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 144 152 94.7 %
Date: 2025-05-24 03:54:53 Functions: 99 104 95.2 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  CPL
       4             :  * Purpose:  Floating point conversion functions. Convert 16- and 24-bit
       5             :  *           floating point numbers into the 32-bit IEEE 754 compliant ones.
       6             :  * Author:   Andrey Kiselev, dron@remotesensing.org
       7             :  *
       8             :  ******************************************************************************
       9             :  * Copyright (c) 2005, Andrey Kiselev <dron@remotesensing.org>
      10             :  * Copyright (c) 2010, Even Rouault <even dot rouault at spatialys.com>
      11             :  *
      12             :  * This code is based on the code from OpenEXR project with the following
      13             :  * copyright:
      14             :  *
      15             :  * Copyright (c) 2002, Industrial Light & Magic, a division of Lucas
      16             :  * Digital Ltd. LLC
      17             :  *
      18             :  * All rights reserved.
      19             :  *
      20             :  * Redistribution and use in source and binary forms, with or without
      21             :  * modification, are permitted provided that the following conditions are
      22             :  * met:
      23             :  * *       Redistributions of source code must retain the above copyright
      24             :  * notice, this list of conditions and the following disclaimer.
      25             :  * *       Redistributions in binary form must reproduce the above
      26             :  * copyright notice, this list of conditions and the following disclaimer
      27             :  * in the documentation and/or other materials provided with the
      28             :  * distribution.
      29             :  * *       Neither the name of Industrial Light & Magic nor the names of
      30             :  * its contributors may be used to endorse or promote products derived
      31             :  * from this software without specific prior written permission.
      32             :  *
      33             :  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
      34             :  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
      35             :  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
      36             :  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
      37             :  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
      38             :  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
      39             :  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
      40             :  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
      41             :  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
      42             :  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
      43             :  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      44             :  *
      45             :  ****************************************************************************/
      46             : 
      47             : #ifndef CPL_FLOAT_H_INCLUDED
      48             : #define CPL_FLOAT_H_INCLUDED
      49             : 
      50             : #include "cpl_port.h"
      51             : 
      52             : #ifdef __cplusplus
      53             : #include <algorithm>
      54             : #include <cmath>
      55             : #include <cstdint>
      56             : #include <cstring>
      57             : #include <limits>
      58             : #ifdef HAVE_STD_FLOAT16_T
      59             : #include <stdfloat>
      60             : #endif
      61             : #endif
      62             : 
      63             : CPL_C_START
      64             : GUInt32 CPL_DLL CPLHalfToFloat(GUInt16 iHalf);
      65             : GUInt32 CPL_DLL CPLTripleToFloat(GUInt32 iTriple);
      66             : CPL_C_END
      67             : 
      68             : #ifdef __cplusplus
      69             : 
      70             : GUInt16 CPL_DLL CPLFloatToHalf(GUInt32 iFloat32, bool &bHasWarned);
      71             : 
      72             : GUInt16 CPL_DLL CPLConvertFloatToHalf(float fFloat32);
      73             : float CPL_DLL CPLConvertHalfToFloat(GUInt16 nHalf);
      74             : 
      75             : namespace cpl
      76             : {
      77             : 
      78             : // We define our own version of `std::numeric_limits` so that we can
      79             : // specialize it for `cpl::Float16` if necessary. Specializing
      80             : // `std::numeric_limits` doesn't always work because some libraries
      81             : // use `std::numeric_limits`, and one cannot specialize a type
      82             : // template after it has been used.
      83             : template <typename T> struct NumericLimits : std::numeric_limits<T>
      84             : {
      85             : };
      86             : 
      87             : #ifndef HAVE_STD_FLOAT16_T
      88             : 
      89             : // Define a type `cpl::Float16`. If the compiler supports it natively
      90             : // (as `_Float16`), then this class is a simple wrapper. Otherwise we
      91             : // store the values in a `GUInt16` as bit pattern.
      92             : 
      93             : //! @cond Doxygen_Suppress
      94             : struct Float16
      95             : {
      96             :     struct make_from_bits_and_value
      97             :     {
      98             :     };
      99             : 
     100             : #ifdef HAVE__FLOAT16
     101             : 
     102             :     // How we represent a `Float16` internally
     103             :     using repr = _Float16;
     104             : 
     105             :     // How we compute on `Float16` values
     106             :     using compute = _Float16;
     107             : 
     108             :     // Create a Float16 in a constexpr manner. Since we can't convert
     109             :     // bits in a constexpr function, we need to take both the bit
     110             :     // pattern and a float value as input, and can then choose which
     111             :     // of the two to use.
     112             :     constexpr Float16(make_from_bits_and_value, CPL_UNUSED std::uint16_t bits,
     113             :                       float fValue)
     114             :         : rValue(repr(fValue))
     115             :     {
     116             :     }
     117             : 
     118             :     static constexpr repr computeToRepr(compute fValue)
     119             :     {
     120             :         return fValue;
     121             :     }
     122             : 
     123             :     static constexpr compute reprToCompute(repr rValue)
     124             :     {
     125             :         return rValue;
     126             :     }
     127             : 
     128             :     template <typename T> static constexpr repr toRepr(T fValue)
     129             :     {
     130             :         return static_cast<repr>(fValue);
     131             :     }
     132             : 
     133             :     template <typename T> static constexpr T fromRepr(repr rValue)
     134             :     {
     135             :         return static_cast<T>(rValue);
     136             :     }
     137             : 
     138             : #else  // #ifndef HAVE__FLOAT16
     139             : 
     140             :     // How we represent a `Float16` internally
     141             :     using repr = std::uint16_t;
     142             : 
     143             :     // How we compute on `Float16` values
     144             :     using compute = float;
     145             : 
     146             :     // Create a Float16 in a constexpr manner. Since we can't convert
     147             :     // bits in a constexpr function, we need to take both the bit
     148             :     // pattern and a float value as input, and can then choose which
     149             :     // of the two to use.
     150        4781 :     constexpr Float16(make_from_bits_and_value, std::uint16_t bits,
     151             :                       CPL_UNUSED float fValue)
     152        4781 :         : rValue(bits)
     153             :     {
     154        4781 :     }
     155             : 
     156     2445769 :     static unsigned float2unsigned(float f)
     157             :     {
     158             :         unsigned u;
     159     2445769 :         std::memcpy(&u, &f, 4);
     160     2445769 :         return u;
     161             :     }
     162             : 
     163     2447791 :     static float unsigned2float(unsigned u)
     164             :     {
     165             :         float f;
     166     2447791 :         std::memcpy(&f, &u, 4);
     167     2447791 :         return f;
     168             :     }
     169             : 
     170             :     // Copied from cpl_float.cpp so that we can inline for performance
     171     2445769 :     static std::uint16_t computeToRepr(float fFloat32)
     172             :     {
     173     2445769 :         std::uint32_t iFloat32 = float2unsigned(fFloat32);
     174             : 
     175     2445769 :         std::uint32_t iSign = (iFloat32 >> 31) & 0x00000001;
     176     2445769 :         std::uint32_t iExponent = (iFloat32 >> 23) & 0x000000ff;
     177     2445769 :         std::uint32_t iMantissa = iFloat32 & 0x007fffff;
     178             : 
     179     2445769 :         if (iExponent == 255)
     180             :         {
     181       58946 :             if (iMantissa == 0)
     182             :             {
     183             :                 // Positive or negative infinity.
     184       58941 :                 return static_cast<std::int16_t>((iSign << 15) | 0x7C00);
     185             :             }
     186             : 
     187             :             // NaN -- preserve sign and significand bits.
     188           5 :             if (iMantissa >> 13)
     189           3 :                 return static_cast<std::int16_t>((iSign << 15) | 0x7C00 |
     190           3 :                                                  (iMantissa >> 13));
     191           2 :             return static_cast<std::int16_t>((iSign << 15) | 0x7E00);
     192             :         }
     193             : 
     194     2386821 :         if (iExponent <= 127 - 15)
     195             :         {
     196             :             // Zero, float32 denormalized number or float32 too small normalized
     197             :             // number
     198      114196 :             if (13 + 1 + 127 - 15 - iExponent >= 32)
     199      110885 :                 return static_cast<std::int16_t>(iSign << 15);
     200             : 
     201             :             // Return a denormalized number
     202        3311 :             return static_cast<std::int16_t>(
     203        3311 :                 (iSign << 15) |
     204        3311 :                 ((iMantissa | 0x00800000) >> (13 + 1 + 127 - 15 - iExponent)));
     205             :         }
     206             : 
     207     2272626 :         if (iExponent - (127 - 15) >= 31)
     208             :         {
     209       18452 :             return static_cast<std::int16_t>((iSign << 15) |
     210       18452 :                                              0x7C00);  // Infinity
     211             :         }
     212             : 
     213             :         // Normalized number.
     214     2254174 :         iExponent = iExponent - (127 - 15);
     215     2254174 :         iMantissa = iMantissa >> 13;
     216             : 
     217             :         // Assemble sign, exponent and mantissa.
     218             :         // coverity[overflow_sink]
     219     2254174 :         return static_cast<std::int16_t>((iSign << 15) | (iExponent << 10) |
     220     2254174 :                                          iMantissa);
     221             :     }
     222             : 
     223             :     // Copied from cpl_float.cpp so that we can inline for performance
     224     2447791 :     static float reprToCompute(std::uint16_t iHalf)
     225             :     {
     226     2447791 :         std::uint32_t iSign = (iHalf >> 15) & 0x00000001;
     227     2447791 :         int iExponent = (iHalf >> 10) & 0x0000001f;
     228     2447791 :         std::uint32_t iMantissa = iHalf & 0x000003ff;
     229             : 
     230     2447791 :         if (iExponent == 31)
     231             :         {
     232       96789 :             if (iMantissa == 0)
     233             :             {
     234             :                 // Positive or negative infinity.
     235       96784 :                 return unsigned2float((iSign << 31) | 0x7f800000);
     236             :             }
     237             : 
     238             :             // NaN -- preserve sign and significand bits.
     239           5 :             return unsigned2float((iSign << 31) | 0x7f800000 |
     240           5 :                                   (iMantissa << 13));
     241             :         }
     242             : 
     243     2351004 :         if (iExponent == 0)
     244             :         {
     245      150494 :             if (iMantissa == 0)
     246             :             {
     247             :                 // Plus or minus zero.
     248      147764 :                 return unsigned2float(iSign << 31);
     249             :             }
     250             : 
     251             :             // Denormalized number -- renormalize it.
     252       18172 :             while (!(iMantissa & 0x00000400))
     253             :             {
     254       15442 :                 iMantissa <<= 1;
     255       15442 :                 iExponent -= 1;
     256             :             }
     257             : 
     258        2730 :             iExponent += 1;
     259        2730 :             iMantissa &= ~0x00000400U;
     260             :         }
     261             : 
     262             :         // Normalized number.
     263     2203233 :         iExponent = iExponent + (127 - 15);
     264     2203233 :         iMantissa = iMantissa << 13;
     265             : 
     266             :         // Assemble sign, exponent and mantissa.
     267             :         /* coverity[overflow_sink] */
     268     2203233 :         return unsigned2float((iSign << 31) |
     269     2203233 :                               (static_cast<std::uint32_t>(iExponent) << 23) |
     270     2203233 :                               iMantissa);
     271             :     }
     272             : 
     273     2445774 :     template <typename T> static repr toRepr(T fValue)
     274             :     {
     275     2445774 :         return computeToRepr(static_cast<compute>(fValue));
     276             :     }
     277             : 
     278      914038 :     template <typename T> static T fromRepr(repr rValue)
     279             :     {
     280      914038 :         return static_cast<T>(reprToCompute(rValue));
     281             :     }
     282             : 
     283             : #endif  // #ifndef HAVE__FLOAT16
     284             : 
     285             :   private:
     286             :     repr rValue;
     287             : 
     288             :   public:
     289     1533748 :     compute get() const
     290             :     {
     291     1533748 :         return reprToCompute(rValue);
     292             :     }
     293             : 
     294             :     // cppcheck-suppress uninitMemberVar
     295             :     Float16() = default;
     296             :     Float16(const Float16 &) = default;
     297             :     Float16(Float16 &&) = default;
     298             :     Float16 &operator=(const Float16 &) = default;
     299             :     Float16 &operator=(Float16 &&) = default;
     300             : 
     301             :     // Constructors and conversion operators
     302             : 
     303             : #ifdef HAVE__FLOAT16
     304             :     // cppcheck-suppress noExplicitConstructor
     305             :     constexpr Float16(_Float16 hfValue) : rValue(hfValue)
     306             :     {
     307             :     }
     308             : 
     309             :     constexpr operator _Float16() const
     310             :     {
     311             :         return rValue;
     312             :     }
     313             : #endif
     314             : 
     315             :     // cppcheck-suppress-macro noExplicitConstructor
     316             : #define GDAL_DEFINE_CONVERSION(TYPE)                                           \
     317             :                                                                                \
     318             :     Float16(TYPE fValue) : rValue(toRepr(fValue))                              \
     319             :     {                                                                          \
     320             :     }                                                                          \
     321             :                                                                                \
     322             :     operator TYPE() const                                                      \
     323             :     {                                                                          \
     324             :         return fromRepr<TYPE>(rValue);                                         \
     325             :     }
     326             : 
     327     1088202 :     GDAL_DEFINE_CONVERSION(float)
     328     1967089 :     GDAL_DEFINE_CONVERSION(double)
     329             :     GDAL_DEFINE_CONVERSION(char)
     330        1066 :     GDAL_DEFINE_CONVERSION(signed char)
     331        8171 :     GDAL_DEFINE_CONVERSION(short)
     332       25245 :     GDAL_DEFINE_CONVERSION(int)
     333       11637 :     GDAL_DEFINE_CONVERSION(long)
     334        4330 :     GDAL_DEFINE_CONVERSION(long long)
     335      243147 :     GDAL_DEFINE_CONVERSION(unsigned char)
     336        3271 :     GDAL_DEFINE_CONVERSION(unsigned short)
     337        3281 :     GDAL_DEFINE_CONVERSION(unsigned int)
     338        2324 :     GDAL_DEFINE_CONVERSION(unsigned long)
     339        2049 :     GDAL_DEFINE_CONVERSION(unsigned long long)
     340             : 
     341             : #undef GDAL_DEFINE_CONVERSION
     342             : 
     343             :     // Arithmetic operators
     344             : 
     345         201 :     friend Float16 operator+(Float16 x)
     346             :     {
     347         201 :         return +x.get();
     348             :     }
     349             : 
     350         963 :     friend Float16 operator-(Float16 x)
     351             :     {
     352         963 :         return -x.get();
     353             :     }
     354             : 
     355             : #define GDAL_DEFINE_ARITHOP(OP)                                                \
     356             :                                                                                \
     357             :     friend Float16 operator OP(Float16 x, Float16 y)                           \
     358             :     {                                                                          \
     359             :         return x.get() OP y.get();                                             \
     360             :     }                                                                          \
     361             :                                                                                \
     362             :     friend double operator OP(double x, Float16 y)                             \
     363             :     {                                                                          \
     364             :         return x OP y.get();                                                   \
     365             :     }                                                                          \
     366             :                                                                                \
     367             :     friend float operator OP(float x, Float16 y)                               \
     368             :     {                                                                          \
     369             :         return x OP y.get();                                                   \
     370             :     }                                                                          \
     371             :                                                                                \
     372             :     friend Float16 operator OP(int x, Float16 y)                               \
     373             :     {                                                                          \
     374             :         return x OP y.get();                                                   \
     375             :     }                                                                          \
     376             :                                                                                \
     377             :     friend double operator OP(Float16 x, double y)                             \
     378             :     {                                                                          \
     379             :         return x.get() OP y;                                                   \
     380             :     }                                                                          \
     381             :                                                                                \
     382             :     friend float operator OP(Float16 x, float y)                               \
     383             :     {                                                                          \
     384             :         return x.get() OP y;                                                   \
     385             :     }                                                                          \
     386             :                                                                                \
     387             :     friend Float16 operator OP(Float16 x, int y)                               \
     388             :     {                                                                          \
     389             :         return x.get() OP y;                                                   \
     390             :     }
     391             : 
     392       67896 :     GDAL_DEFINE_ARITHOP(+)
     393       40818 :     GDAL_DEFINE_ARITHOP(-)
     394       40401 :     GDAL_DEFINE_ARITHOP(*)
     395       61257 :     GDAL_DEFINE_ARITHOP(/)
     396             : 
     397             : #undef GDAL_DEFINE_ARITHOP
     398             : 
     399             :     // Comparison operators
     400             : 
     401             : #define GDAL_DEFINE_COMPARISON(OP)                                             \
     402             :                                                                                \
     403             :     friend bool operator OP(Float16 x, Float16 y)                              \
     404             :     {                                                                          \
     405             :         return x.get() OP y.get();                                             \
     406             :     }                                                                          \
     407             :                                                                                \
     408             :     friend bool operator OP(float x, Float16 y)                                \
     409             :     {                                                                          \
     410             :         return x OP y.get();                                                   \
     411             :     }                                                                          \
     412             :                                                                                \
     413             :     friend bool operator OP(double x, Float16 y)                               \
     414             :     {                                                                          \
     415             :         return x OP y.get();                                                   \
     416             :     }                                                                          \
     417             :                                                                                \
     418             :     friend bool operator OP(int x, Float16 y)                                  \
     419             :     {                                                                          \
     420             :         return x OP y.get();                                                   \
     421             :     }                                                                          \
     422             :                                                                                \
     423             :     friend bool operator OP(Float16 x, float y)                                \
     424             :     {                                                                          \
     425             :         return x.get() OP y;                                                   \
     426             :     }                                                                          \
     427             :                                                                                \
     428             :     friend bool operator OP(Float16 x, double y)                               \
     429             :     {                                                                          \
     430             :         return x.get() OP y;                                                   \
     431             :     }                                                                          \
     432             :                                                                                \
     433             :     friend bool operator OP(Float16 x, int y)                                  \
     434             :     {                                                                          \
     435             :         return x.get() OP y;                                                   \
     436             :     }
     437             : 
     438      421768 :     GDAL_DEFINE_COMPARISON(==)
     439       40409 :     GDAL_DEFINE_COMPARISON(!=)
     440       42740 :     GDAL_DEFINE_COMPARISON(<)
     441       48120 :     GDAL_DEFINE_COMPARISON(>)
     442       41719 :     GDAL_DEFINE_COMPARISON(<=)
     443       41984 :     GDAL_DEFINE_COMPARISON(>=)
     444             : 
     445             : #undef GDAL_DEFINE_COMPARISON
     446             : 
     447             :     // Standard math functions
     448             : 
     449       40602 :     friend bool isfinite(Float16 x)
     450             :     {
     451             :         using std::isfinite;
     452       40602 :         return isfinite(float(x));
     453             :     }
     454             : 
     455        4184 :     friend bool isinf(Float16 x)
     456             :     {
     457             :         using std::isinf;
     458        4184 :         return isinf(float(x));
     459             :     }
     460             : 
     461        4753 :     friend bool isnan(Float16 x)
     462             :     {
     463             :         using std::isnan;
     464        4753 :         return isnan(float(x));
     465             :     }
     466             : 
     467             :     friend bool isnormal(Float16 x)
     468             :     {
     469             :         using std::isnormal;
     470             :         return isnormal(float(x));
     471             :     }
     472             : 
     473           0 :     friend bool signbit(Float16 x)
     474             :     {
     475             :         using std::signbit;
     476           0 :         return signbit(float(x));
     477             :     }
     478             : 
     479         201 :     friend Float16 abs(Float16 x)
     480             :     {
     481             :         using std::abs;
     482         201 :         return Float16(abs(float(x)));
     483             :     }
     484             : 
     485         201 :     friend Float16 cbrt(Float16 x)
     486             :     {
     487             :         using std::cbrt;
     488         201 :         return Float16(cbrt(float(x)));
     489             :     }
     490             : 
     491         201 :     friend Float16 ceil(Float16 x)
     492             :     {
     493             :         using std::ceil;
     494         201 :         return Float16(ceil(float(x)));
     495             :     }
     496             : 
     497             :     friend Float16 copysign(Float16 x, Float16 y)
     498             :     {
     499             :         using std::copysign;
     500             :         return Float16(copysign(float(x), float(y)));
     501             :     }
     502             : 
     503       21258 :     friend Float16 fabs(Float16 x)
     504             :     {
     505             :         using std::fabs;
     506       21258 :         return Float16(fabs(float(x)));
     507             :     }
     508             : 
     509         201 :     friend Float16 floor(Float16 x)
     510             :     {
     511             :         using std::floor;
     512         201 :         return Float16(floor(float(x)));
     513             :     }
     514             : 
     515       40401 :     friend Float16 fmax(Float16 x, Float16 y)
     516             :     {
     517             :         using std::fmax;
     518       40401 :         return Float16(fmax(float(x), float(y)));
     519             :     }
     520             : 
     521       40401 :     friend Float16 fmin(Float16 x, Float16 y)
     522             :     {
     523             :         using std::fmin;
     524       40401 :         return Float16(fmin(float(x), float(y)));
     525             :     }
     526             : 
     527       40401 :     friend Float16 hypot(Float16 x, Float16 y)
     528             :     {
     529             :         using std::hypot;
     530       40401 :         return Float16(hypot(float(x), float(y)));
     531             :     }
     532             : 
     533       40401 :     friend Float16 max(Float16 x, Float16 y)
     534             :     {
     535             :         using std::max;
     536       40401 :         return Float16(max(float(x), float(y)));
     537             :     }
     538             : 
     539       40401 :     friend Float16 min(Float16 x, Float16 y)
     540             :     {
     541             :         using std::min;
     542       40401 :         return Float16(min(float(x), float(y)));
     543             :     }
     544             : 
     545             :     // Adapted from the LLVM Project, under the Apache License v2.0
     546           8 :     friend Float16 nextafter(Float16 x, Float16 y)
     547             :     {
     548           8 :         if (isnan(x))
     549           0 :             return x;
     550           8 :         if (isnan(y))
     551           0 :             return y;
     552           8 :         if (x == y)
     553           0 :             return y;
     554             : 
     555             :         std::uint16_t bits;
     556           8 :         if (x != Float16(0))
     557             :         {
     558           8 :             std::memcpy(&bits, &x.rValue, 2);
     559           8 :             if ((x < y) == (x > Float16(0)))
     560           2 :                 ++bits;
     561             :             else
     562           6 :                 --bits;
     563             :         }
     564             :         else
     565             :         {
     566           0 :             bits = (signbit(y) << 15) | 0x0001;
     567             :         }
     568             : 
     569             :         Float16 r;
     570           8 :         std::memcpy(&r.rValue, &bits, 2);
     571             : 
     572           8 :         return r;
     573             :     }
     574             : 
     575       40401 :     friend Float16 pow(Float16 x, Float16 y)
     576             :     {
     577             :         using std::pow;
     578       40401 :         return Float16(pow(float(x), float(y)));
     579             :     }
     580             : 
     581       40401 :     friend Float16 pow(Float16 x, int n)
     582             :     {
     583             :         using std::pow;
     584       40401 :         return Float16(pow(float(x), n));
     585             :     }
     586             : 
     587         201 :     friend Float16 round(Float16 x)
     588             :     {
     589             :         using std::round;
     590         201 :         return Float16(round(float(x)));
     591             :     }
     592             : 
     593         101 :     friend Float16 sqrt(Float16 x)
     594             :     {
     595             :         using std::sqrt;
     596         101 :         return Float16(sqrt(float(x)));
     597             :     }
     598             : };
     599             : 
     600             : template <> struct NumericLimits<Float16>
     601             : {
     602             :     static constexpr bool is_specialized = true;
     603             :     static constexpr bool is_signed = true;
     604             :     static constexpr bool is_integer = false;
     605             :     static constexpr bool is_exact = false;
     606             :     static constexpr bool has_infinity = true;
     607             :     static constexpr bool has_quiet_NaN = true;
     608             :     static constexpr bool has_signaling_NaN = true;
     609             :     static constexpr bool has_denorm = true;
     610             :     static constexpr bool is_iec559 = true;
     611             : 
     612             :     static constexpr int digits = 11;
     613             :     static constexpr int digits10 = 3;
     614             :     static constexpr int max_digits10 = 5;
     615             :     static constexpr int radix = 2;
     616             : 
     617           0 :     static constexpr Float16 epsilon()
     618             :     {
     619           0 :         return Float16(Float16::make_from_bits_and_value{}, 0x1400, 0.000977f);
     620             :     }
     621             : 
     622             :     static constexpr Float16 min()
     623             :     {
     624             :         return Float16(Float16::make_from_bits_and_value{}, 0x0001, 6.0e-8f);
     625             :     }
     626             : 
     627        1626 :     static constexpr Float16 lowest()
     628             :     {
     629        1626 :         return Float16(Float16::make_from_bits_and_value{}, 0xfbff, -65504.0f);
     630             :     }
     631             : 
     632        3150 :     static constexpr Float16 max()
     633             :     {
     634        3150 :         return Float16(Float16::make_from_bits_and_value{}, 0x7bff, +65504.0f);
     635             :     }
     636             : 
     637           5 :     static constexpr Float16 infinity()
     638             :     {
     639           5 :         return Float16(Float16::make_from_bits_and_value{}, 0x7c00,
     640           5 :                        std::numeric_limits<float>::infinity());
     641             :     }
     642             : 
     643             :     static constexpr Float16 quiet_NaN()
     644             :     {
     645             :         return Float16(Float16::make_from_bits_and_value{}, 0x7e00,
     646             :                        std::numeric_limits<float>::quiet_NaN());
     647             :     }
     648             : 
     649             :     static constexpr Float16 signaling_NaN()
     650             :     {
     651             :         return Float16(Float16::make_from_bits_and_value{}, 0xfe00,
     652             :                        std::numeric_limits<float>::signaling_NaN());
     653             :     }
     654             : };
     655             : 
     656             : //! @endcond
     657             : 
     658             : #endif  // #ifndef HAVE_STD_FLOAT16_T
     659             : 
     660             : }  // namespace cpl
     661             : 
     662             : #ifdef HAVE_STD_FLOAT16_T
     663             : using GFloat16 = std::float16_t;
     664             : #else
     665             : using GFloat16 = cpl::Float16;
     666             : #endif
     667             : 
     668             : // Define some GDAL wrappers. Their C equivalents are defined in `cpl_port.h`.
     669             : // (These wrappers are not necessary any more in C++, one can always
     670             : // call `isnan` etc directly.)
     671             : 
     672   315520571 : template <typename T> constexpr int CPLIsNan(T x)
     673             : {
     674             :     // We need to write `using std::isnan` instead of directly using
     675             :     // `std::isnan` because `std::isnan` only supports the types
     676             :     // `float` and `double`. The `isnan` for `cpl::Float16` is found in the
     677             :     // `cpl` namespace via argument-dependent lookup
     678             :     // <https://en.cppreference.com/w/cpp/language/adl>.
     679             :     using std::isnan;
     680   315520571 :     return isnan(x);
     681             : }
     682             : 
     683       44081 : template <typename T> constexpr int CPLIsInf(T x)
     684             : {
     685             :     using std::isinf;
     686       44081 :     return isinf(x);
     687             : }
     688             : 
     689             : template <typename T> constexpr int CPLIsFinite(T x)
     690             : {
     691             :     using std::isfinite;
     692             :     return isfinite(x);
     693             : }
     694             : 
     695             : #endif  // #ifdef __cplusplus
     696             : 
     697             : double CPL_DLL CPLGreatestCommonDivisor(double x, double y);
     698             : 
     699             : #endif  // CPL_FLOAT_H_INCLUDED

Generated by: LCOV version 1.14