Coverage Report

Created: 2025-06-22 06:59

/src/gdal/port/cpl_float.h
Line
Count
Source (jump to first uncovered line)
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
#if defined(__F16C__)
76
#include <immintrin.h>
77
#ifndef GDALCopyXMMToInt16_defined
78
#define GDALCopyXMMToInt16_defined
79
80
static inline void GDALCopyXMMToInt16(const __m128i xmm, void *pDest)
81
{
82
    GInt16 i = static_cast<GInt16>(_mm_extract_epi16(xmm, 0));
83
    memcpy(pDest, &i, 2);
84
}
85
#endif
86
#endif
87
88
namespace cpl
89
{
90
91
// We define our own version of `std::numeric_limits` so that we can
92
// specialize it for `cpl::Float16` if necessary. Specializing
93
// `std::numeric_limits` doesn't always work because some libraries
94
// use `std::numeric_limits`, and one cannot specialize a type
95
// template after it has been used.
96
template <typename T> struct NumericLimits : std::numeric_limits<T>
97
{
98
};
99
100
#ifndef HAVE_STD_FLOAT16_T
101
102
// Define a type `cpl::Float16`. If the compiler supports it natively
103
// (as `_Float16`), then this class is a simple wrapper. Otherwise we
104
// store the values in a `GUInt16` as bit pattern.
105
106
//! @cond Doxygen_Suppress
107
struct Float16
108
{
109
    struct make_from_bits_and_value
110
    {
111
    };
112
113
#ifdef HAVE__FLOAT16
114
115
    // How we represent a `Float16` internally
116
    using repr = _Float16;
117
118
    // How we compute on `Float16` values
119
    using compute = _Float16;
120
121
    // Create a Float16 in a constexpr manner. Since we can't convert
122
    // bits in a constexpr function, we need to take both the bit
123
    // pattern and a float value as input, and can then choose which
124
    // of the two to use.
125
    constexpr Float16(make_from_bits_and_value, CPL_UNUSED std::uint16_t bits,
126
                      float fValue)
127
0
        : rValue(repr(fValue))
128
0
    {
129
0
    }
130
131
    static constexpr repr computeToRepr(compute fValue)
132
0
    {
133
0
        return fValue;
134
0
    }
135
136
    static constexpr compute reprToCompute(repr rValue)
137
0
    {
138
0
        return rValue;
139
0
    }
140
141
    template <typename T> static constexpr repr toRepr(T fValue)
142
0
    {
143
0
        return static_cast<repr>(fValue);
144
0
    }
Unexecuted instantiation: _ZN3cpl7Float166toReprIfEEDF16_T_
Unexecuted instantiation: _ZN3cpl7Float166toReprIdEEDF16_T_
Unexecuted instantiation: _ZN3cpl7Float166toReprIcEEDF16_T_
Unexecuted instantiation: _ZN3cpl7Float166toReprIaEEDF16_T_
Unexecuted instantiation: _ZN3cpl7Float166toReprIsEEDF16_T_
Unexecuted instantiation: _ZN3cpl7Float166toReprIiEEDF16_T_
Unexecuted instantiation: _ZN3cpl7Float166toReprIlEEDF16_T_
Unexecuted instantiation: _ZN3cpl7Float166toReprIxEEDF16_T_
Unexecuted instantiation: _ZN3cpl7Float166toReprIhEEDF16_T_
Unexecuted instantiation: _ZN3cpl7Float166toReprItEEDF16_T_
Unexecuted instantiation: _ZN3cpl7Float166toReprIjEEDF16_T_
Unexecuted instantiation: _ZN3cpl7Float166toReprImEEDF16_T_
Unexecuted instantiation: _ZN3cpl7Float166toReprIyEEDF16_T_
145
146
    template <typename T> static constexpr T fromRepr(repr rValue)
147
0
    {
148
0
        return static_cast<T>(rValue);
149
0
    }
Unexecuted instantiation: _ZN3cpl7Float168fromReprIfEET_DF16_
Unexecuted instantiation: _ZN3cpl7Float168fromReprIdEET_DF16_
Unexecuted instantiation: _ZN3cpl7Float168fromReprIcEET_DF16_
Unexecuted instantiation: _ZN3cpl7Float168fromReprIaEET_DF16_
Unexecuted instantiation: _ZN3cpl7Float168fromReprIsEET_DF16_
Unexecuted instantiation: _ZN3cpl7Float168fromReprIiEET_DF16_
Unexecuted instantiation: _ZN3cpl7Float168fromReprIlEET_DF16_
Unexecuted instantiation: _ZN3cpl7Float168fromReprIxEET_DF16_
Unexecuted instantiation: _ZN3cpl7Float168fromReprIhEET_DF16_
Unexecuted instantiation: _ZN3cpl7Float168fromReprItEET_DF16_
Unexecuted instantiation: _ZN3cpl7Float168fromReprIjEET_DF16_
Unexecuted instantiation: _ZN3cpl7Float168fromReprImEET_DF16_
Unexecuted instantiation: _ZN3cpl7Float168fromReprIyEET_DF16_
150
151
#else  // #ifndef HAVE__FLOAT16
152
153
    // How we represent a `Float16` internally
154
    using repr = std::uint16_t;
155
156
    // How we compute on `Float16` values
157
    using compute = float;
158
159
    // Create a Float16 in a constexpr manner. Since we can't convert
160
    // bits in a constexpr function, we need to take both the bit
161
    // pattern and a float value as input, and can then choose which
162
    // of the two to use.
163
    constexpr Float16(make_from_bits_and_value, std::uint16_t bits,
164
                      CPL_UNUSED float fValue)
165
        : rValue(bits)
166
    {
167
    }
168
169
    static unsigned float2unsigned(float f)
170
    {
171
        unsigned u;
172
        std::memcpy(&u, &f, 4);
173
        return u;
174
    }
175
176
    static float unsigned2float(unsigned u)
177
    {
178
        float f;
179
        std::memcpy(&f, &u, 4);
180
        return f;
181
    }
182
183
    // Copied from cpl_float.cpp so that we can inline for performance
184
    static std::uint16_t computeToRepr(float fFloat32)
185
    {
186
        std::uint32_t iFloat32 = float2unsigned(fFloat32);
187
188
        std::uint32_t iSign = (iFloat32 >> 31) & 0x00000001;
189
        std::uint32_t iExponent = (iFloat32 >> 23) & 0x000000ff;
190
        std::uint32_t iMantissa = iFloat32 & 0x007fffff;
191
192
        if (iExponent == 255)
193
        {
194
            if (iMantissa == 0)
195
            {
196
                // Positive or negative infinity.
197
                return static_cast<std::int16_t>((iSign << 15) | 0x7C00);
198
            }
199
200
            // NaN -- preserve sign and significand bits.
201
            if (iMantissa >> 13)
202
                return static_cast<std::int16_t>((iSign << 15) | 0x7C00 |
203
                                                 (iMantissa >> 13));
204
            return static_cast<std::int16_t>((iSign << 15) | 0x7E00);
205
        }
206
207
        if (iExponent <= 127 - 15)
208
        {
209
            // Zero, float32 denormalized number or float32 too small normalized
210
            // number
211
            if (13 + 1 + 127 - 15 - iExponent >= 32)
212
                return static_cast<std::int16_t>(iSign << 15);
213
214
            // Return a denormalized number
215
            return static_cast<std::int16_t>(
216
                (iSign << 15) |
217
                ((iMantissa | 0x00800000) >> (13 + 1 + 127 - 15 - iExponent)));
218
        }
219
220
        if (iExponent - (127 - 15) >= 31)
221
        {
222
            return static_cast<std::int16_t>((iSign << 15) |
223
                                             0x7C00);  // Infinity
224
        }
225
226
        // Normalized number.
227
        iExponent = iExponent - (127 - 15);
228
        iMantissa = iMantissa >> 13;
229
230
        // Assemble sign, exponent and mantissa.
231
        // coverity[overflow_sink]
232
        return static_cast<std::int16_t>((iSign << 15) | (iExponent << 10) |
233
                                         iMantissa);
234
    }
235
236
    // Copied from cpl_float.cpp so that we can inline for performance
237
    static float reprToCompute(std::uint16_t iHalf)
238
    {
239
        std::uint32_t iSign = (iHalf >> 15) & 0x00000001;
240
        int iExponent = (iHalf >> 10) & 0x0000001f;
241
        std::uint32_t iMantissa = iHalf & 0x000003ff;
242
243
        if (iExponent == 31)
244
        {
245
            if (iMantissa == 0)
246
            {
247
                // Positive or negative infinity.
248
                return unsigned2float((iSign << 31) | 0x7f800000);
249
            }
250
251
            // NaN -- preserve sign and significand bits.
252
            return unsigned2float((iSign << 31) | 0x7f800000 |
253
                                  (iMantissa << 13));
254
        }
255
256
        if (iExponent == 0)
257
        {
258
            if (iMantissa == 0)
259
            {
260
                // Plus or minus zero.
261
                return unsigned2float(iSign << 31);
262
            }
263
264
            // Denormalized number -- renormalize it.
265
            while (!(iMantissa & 0x00000400))
266
            {
267
                iMantissa <<= 1;
268
                iExponent -= 1;
269
            }
270
271
            iExponent += 1;
272
            iMantissa &= ~0x00000400U;
273
        }
274
275
        // Normalized number.
276
        iExponent = iExponent + (127 - 15);
277
        iMantissa = iMantissa << 13;
278
279
        // Assemble sign, exponent and mantissa.
280
        /* coverity[overflow_sink] */
281
        return unsigned2float((iSign << 31) |
282
                              (static_cast<std::uint32_t>(iExponent) << 23) |
283
                              iMantissa);
284
    }
285
286
    template <typename T> static repr toRepr(T value)
287
    {
288
#ifdef __F16C__
289
        float fValue = static_cast<float>(value);
290
        __m128 xmm_float = _mm_load_ss(&fValue);
291
        const __m128i xmm_hfloat =
292
            _mm_cvtps_ph(xmm_float, _MM_FROUND_TO_NEAREST_INT);
293
        repr hfValueOut;
294
        GDALCopyXMMToInt16(xmm_hfloat, &hfValueOut);
295
        return hfValueOut;
296
#else
297
        return computeToRepr(static_cast<compute>(value));
298
#endif
299
    }
300
301
    template <typename T> static T fromRepr(repr rValue)
302
    {
303
#ifdef __F16C__
304
        __m128i xmm;
305
        memcpy(&xmm, &rValue, sizeof(repr));
306
        float fValueOut;
307
        _mm_store_ss(&fValueOut, _mm_cvtph_ps(xmm));
308
        return static_cast<T>(fValueOut);
309
#else
310
        return static_cast<T>(reprToCompute(rValue));
311
#endif
312
    }
313
314
#endif  // #ifndef HAVE__FLOAT16
315
316
  private:
317
    repr rValue;
318
319
  public:
320
    compute get() const
321
0
    {
322
0
        return reprToCompute(rValue);
323
0
    }
324
325
    // cppcheck-suppress uninitMemberVar
326
    Float16() = default;
327
    Float16(const Float16 &) = default;
328
    Float16(Float16 &&) = default;
329
    Float16 &operator=(const Float16 &) = default;
330
    Float16 &operator=(Float16 &&) = default;
331
332
    // Constructors and conversion operators
333
334
#ifdef HAVE__FLOAT16
335
    // cppcheck-suppress noExplicitConstructor
336
0
    constexpr Float16(_Float16 hfValue) : rValue(hfValue)
337
0
    {
338
0
    }
339
340
    constexpr operator _Float16() const
341
0
    {
342
0
        return rValue;
343
0
    }
344
#endif
345
346
    // cppcheck-suppress-macro noExplicitConstructor
347
#define GDAL_DEFINE_CONVERSION(TYPE)                                           \
348
                                                                               \
349
0
    Float16(TYPE fValue) : rValue(toRepr(fValue))                              \
350
0
    {                                                                          \
351
0
    }                                                                          \
Unexecuted instantiation: cpl::Float16::Float16(float)
Unexecuted instantiation: cpl::Float16::Float16(double)
Unexecuted instantiation: cpl::Float16::Float16(signed char)
Unexecuted instantiation: cpl::Float16::Float16(short)
Unexecuted instantiation: cpl::Float16::Float16(int)
Unexecuted instantiation: cpl::Float16::Float16(long)
Unexecuted instantiation: cpl::Float16::Float16(unsigned char)
Unexecuted instantiation: cpl::Float16::Float16(unsigned short)
Unexecuted instantiation: cpl::Float16::Float16(unsigned int)
Unexecuted instantiation: cpl::Float16::Float16(unsigned long)
Unexecuted instantiation: cpl::Float16::Float16(char)
Unexecuted instantiation: cpl::Float16::Float16(long long)
Unexecuted instantiation: cpl::Float16::Float16(unsigned long long)
352
                                                                               \
353
    operator TYPE() const                                                      \
354
0
    {                                                                          \
355
0
        return fromRepr<TYPE>(rValue);                                         \
356
0
    }
Unexecuted instantiation: cpl::Float16::operator float() const
Unexecuted instantiation: cpl::Float16::operator double() const
Unexecuted instantiation: cpl::Float16::operator char() const
Unexecuted instantiation: cpl::Float16::operator signed char() const
Unexecuted instantiation: cpl::Float16::operator short() const
Unexecuted instantiation: cpl::Float16::operator int() const
Unexecuted instantiation: cpl::Float16::operator long() const
Unexecuted instantiation: cpl::Float16::operator long long() const
Unexecuted instantiation: cpl::Float16::operator unsigned char() const
Unexecuted instantiation: cpl::Float16::operator unsigned short() const
Unexecuted instantiation: cpl::Float16::operator unsigned int() const
Unexecuted instantiation: cpl::Float16::operator unsigned long() const
Unexecuted instantiation: cpl::Float16::operator unsigned long long() const
357
358
    GDAL_DEFINE_CONVERSION(float)
359
    GDAL_DEFINE_CONVERSION(double)
360
    GDAL_DEFINE_CONVERSION(char)
361
    GDAL_DEFINE_CONVERSION(signed char)
362
    GDAL_DEFINE_CONVERSION(short)
363
    GDAL_DEFINE_CONVERSION(int)
364
    GDAL_DEFINE_CONVERSION(long)
365
    GDAL_DEFINE_CONVERSION(long long)
366
    GDAL_DEFINE_CONVERSION(unsigned char)
367
    GDAL_DEFINE_CONVERSION(unsigned short)
368
    GDAL_DEFINE_CONVERSION(unsigned int)
369
    GDAL_DEFINE_CONVERSION(unsigned long)
370
    GDAL_DEFINE_CONVERSION(unsigned long long)
371
372
#undef GDAL_DEFINE_CONVERSION
373
374
    // Arithmetic operators
375
376
    friend Float16 operator+(Float16 x)
377
0
    {
378
0
        return +x.get();
379
0
    }
380
381
    friend Float16 operator-(Float16 x)
382
0
    {
383
0
        return -x.get();
384
0
    }
385
386
#define GDAL_DEFINE_ARITHOP(OP)                                                \
387
                                                                               \
388
    friend Float16 operator OP(Float16 x, Float16 y)                           \
389
0
    {                                                                          \
390
0
        return x.get() OP y.get();                                             \
391
0
    }                                                                          \
Unexecuted instantiation: cpl::operator+(cpl::Float16, cpl::Float16)
Unexecuted instantiation: cpl::operator-(cpl::Float16, cpl::Float16)
Unexecuted instantiation: cpl::operator*(cpl::Float16, cpl::Float16)
Unexecuted instantiation: cpl::operator/(cpl::Float16, cpl::Float16)
392
                                                                               \
393
    friend double operator OP(double x, Float16 y)                             \
394
0
    {                                                                          \
395
0
        return x OP y.get();                                                   \
396
0
    }                                                                          \
Unexecuted instantiation: cpl::operator+(double, cpl::Float16)
Unexecuted instantiation: cpl::operator-(double, cpl::Float16)
Unexecuted instantiation: cpl::operator*(double, cpl::Float16)
Unexecuted instantiation: cpl::operator/(double, cpl::Float16)
397
                                                                               \
398
    friend float operator OP(float x, Float16 y)                               \
399
0
    {                                                                          \
400
0
        return x OP y.get();                                                   \
401
0
    }                                                                          \
Unexecuted instantiation: cpl::operator+(float, cpl::Float16)
Unexecuted instantiation: cpl::operator-(float, cpl::Float16)
Unexecuted instantiation: cpl::operator*(float, cpl::Float16)
Unexecuted instantiation: cpl::operator/(float, cpl::Float16)
402
                                                                               \
403
    friend Float16 operator OP(int x, Float16 y)                               \
404
0
    {                                                                          \
405
0
        return x OP y.get();                                                   \
406
0
    }                                                                          \
Unexecuted instantiation: cpl::operator+(int, cpl::Float16)
Unexecuted instantiation: cpl::operator-(int, cpl::Float16)
Unexecuted instantiation: cpl::operator*(int, cpl::Float16)
Unexecuted instantiation: cpl::operator/(int, cpl::Float16)
407
                                                                               \
408
    friend double operator OP(Float16 x, double y)                             \
409
0
    {                                                                          \
410
0
        return x.get() OP y;                                                   \
411
0
    }                                                                          \
Unexecuted instantiation: cpl::operator+(cpl::Float16, double)
Unexecuted instantiation: cpl::operator-(cpl::Float16, double)
Unexecuted instantiation: cpl::operator*(cpl::Float16, double)
Unexecuted instantiation: cpl::operator/(cpl::Float16, double)
412
                                                                               \
413
    friend float operator OP(Float16 x, float y)                               \
414
0
    {                                                                          \
415
0
        return x.get() OP y;                                                   \
416
0
    }                                                                          \
Unexecuted instantiation: cpl::operator+(cpl::Float16, float)
Unexecuted instantiation: cpl::operator-(cpl::Float16, float)
Unexecuted instantiation: cpl::operator*(cpl::Float16, float)
Unexecuted instantiation: cpl::operator/(cpl::Float16, float)
417
                                                                               \
418
    friend Float16 operator OP(Float16 x, int y)                               \
419
0
    {                                                                          \
420
0
        return x.get() OP y;                                                   \
421
0
    }
Unexecuted instantiation: cpl::operator+(cpl::Float16, int)
Unexecuted instantiation: cpl::operator-(cpl::Float16, int)
Unexecuted instantiation: cpl::operator*(cpl::Float16, int)
Unexecuted instantiation: cpl::operator/(cpl::Float16, int)
422
423
    GDAL_DEFINE_ARITHOP(+)
424
    GDAL_DEFINE_ARITHOP(-)
425
    GDAL_DEFINE_ARITHOP(*)
426
    GDAL_DEFINE_ARITHOP(/)
427
428
#undef GDAL_DEFINE_ARITHOP
429
430
    // Comparison operators
431
432
#define GDAL_DEFINE_COMPARISON(OP)                                             \
433
                                                                               \
434
    friend bool operator OP(Float16 x, Float16 y)                              \
435
0
    {                                                                          \
436
0
        return x.get() OP y.get();                                             \
437
0
    }                                                                          \
Unexecuted instantiation: cpl::operator==(cpl::Float16, cpl::Float16)
Unexecuted instantiation: cpl::operator!=(cpl::Float16, cpl::Float16)
Unexecuted instantiation: cpl::operator<(cpl::Float16, cpl::Float16)
Unexecuted instantiation: cpl::operator>(cpl::Float16, cpl::Float16)
Unexecuted instantiation: cpl::operator<=(cpl::Float16, cpl::Float16)
Unexecuted instantiation: cpl::operator>=(cpl::Float16, cpl::Float16)
438
                                                                               \
439
    friend bool operator OP(float x, Float16 y)                                \
440
0
    {                                                                          \
441
0
        return x OP y.get();                                                   \
442
0
    }                                                                          \
Unexecuted instantiation: cpl::operator==(float, cpl::Float16)
Unexecuted instantiation: cpl::operator!=(float, cpl::Float16)
Unexecuted instantiation: cpl::operator<(float, cpl::Float16)
Unexecuted instantiation: cpl::operator>(float, cpl::Float16)
Unexecuted instantiation: cpl::operator<=(float, cpl::Float16)
Unexecuted instantiation: cpl::operator>=(float, cpl::Float16)
443
                                                                               \
444
    friend bool operator OP(double x, Float16 y)                               \
445
0
    {                                                                          \
446
0
        return x OP y.get();                                                   \
447
0
    }                                                                          \
Unexecuted instantiation: cpl::operator==(double, cpl::Float16)
Unexecuted instantiation: cpl::operator!=(double, cpl::Float16)
Unexecuted instantiation: cpl::operator<(double, cpl::Float16)
Unexecuted instantiation: cpl::operator>(double, cpl::Float16)
Unexecuted instantiation: cpl::operator<=(double, cpl::Float16)
Unexecuted instantiation: cpl::operator>=(double, cpl::Float16)
448
                                                                               \
449
    friend bool operator OP(int x, Float16 y)                                  \
450
0
    {                                                                          \
451
0
        return x OP y.get();                                                   \
452
0
    }                                                                          \
Unexecuted instantiation: cpl::operator==(int, cpl::Float16)
Unexecuted instantiation: cpl::operator!=(int, cpl::Float16)
Unexecuted instantiation: cpl::operator<(int, cpl::Float16)
Unexecuted instantiation: cpl::operator>(int, cpl::Float16)
Unexecuted instantiation: cpl::operator<=(int, cpl::Float16)
Unexecuted instantiation: cpl::operator>=(int, cpl::Float16)
453
                                                                               \
454
    friend bool operator OP(Float16 x, float y)                                \
455
0
    {                                                                          \
456
0
        return x.get() OP y;                                                   \
457
0
    }                                                                          \
Unexecuted instantiation: cpl::operator==(cpl::Float16, float)
Unexecuted instantiation: cpl::operator!=(cpl::Float16, float)
Unexecuted instantiation: cpl::operator<(cpl::Float16, float)
Unexecuted instantiation: cpl::operator>(cpl::Float16, float)
Unexecuted instantiation: cpl::operator<=(cpl::Float16, float)
Unexecuted instantiation: cpl::operator>=(cpl::Float16, float)
458
                                                                               \
459
    friend bool operator OP(Float16 x, double y)                               \
460
0
    {                                                                          \
461
0
        return x.get() OP y;                                                   \
462
0
    }                                                                          \
Unexecuted instantiation: cpl::operator==(cpl::Float16, double)
Unexecuted instantiation: cpl::operator!=(cpl::Float16, double)
Unexecuted instantiation: cpl::operator<(cpl::Float16, double)
Unexecuted instantiation: cpl::operator>(cpl::Float16, double)
Unexecuted instantiation: cpl::operator<=(cpl::Float16, double)
Unexecuted instantiation: cpl::operator>=(cpl::Float16, double)
463
                                                                               \
464
    friend bool operator OP(Float16 x, int y)                                  \
465
0
    {                                                                          \
466
0
        return x.get() OP y;                                                   \
467
0
    }
Unexecuted instantiation: cpl::operator==(cpl::Float16, int)
Unexecuted instantiation: cpl::operator!=(cpl::Float16, int)
Unexecuted instantiation: cpl::operator<(cpl::Float16, int)
Unexecuted instantiation: cpl::operator>(cpl::Float16, int)
Unexecuted instantiation: cpl::operator<=(cpl::Float16, int)
Unexecuted instantiation: cpl::operator>=(cpl::Float16, int)
468
469
    GDAL_DEFINE_COMPARISON(==)
470
    GDAL_DEFINE_COMPARISON(!=)
471
    GDAL_DEFINE_COMPARISON(<)
472
    GDAL_DEFINE_COMPARISON(>)
473
    GDAL_DEFINE_COMPARISON(<=)
474
    GDAL_DEFINE_COMPARISON(>=)
475
476
#undef GDAL_DEFINE_COMPARISON
477
478
    // Standard math functions
479
480
    friend bool isfinite(Float16 x)
481
0
    {
482
0
        using std::isfinite;
483
0
        return isfinite(float(x));
484
0
    }
485
486
    friend bool isinf(Float16 x)
487
0
    {
488
0
        using std::isinf;
489
0
        return isinf(float(x));
490
0
    }
491
492
    friend bool isnan(Float16 x)
493
0
    {
494
0
        using std::isnan;
495
0
        return isnan(float(x));
496
0
    }
497
498
    friend bool isnormal(Float16 x)
499
0
    {
500
0
        using std::isnormal;
501
0
        return isnormal(float(x));
502
0
    }
503
504
    friend bool signbit(Float16 x)
505
0
    {
506
0
        using std::signbit;
507
0
        return signbit(float(x));
508
0
    }
509
510
    friend Float16 abs(Float16 x)
511
0
    {
512
0
        using std::abs;
513
0
        return Float16(abs(float(x)));
514
0
    }
515
516
    friend Float16 cbrt(Float16 x)
517
0
    {
518
0
        using std::cbrt;
519
0
        return Float16(cbrt(float(x)));
520
0
    }
521
522
    friend Float16 ceil(Float16 x)
523
0
    {
524
0
        using std::ceil;
525
0
        return Float16(ceil(float(x)));
526
0
    }
527
528
    friend Float16 copysign(Float16 x, Float16 y)
529
0
    {
530
0
        using std::copysign;
531
0
        return Float16(copysign(float(x), float(y)));
532
0
    }
533
534
    friend Float16 fabs(Float16 x)
535
0
    {
536
0
        using std::fabs;
537
0
        return Float16(fabs(float(x)));
538
0
    }
539
540
    friend Float16 floor(Float16 x)
541
0
    {
542
0
        using std::floor;
543
0
        return Float16(floor(float(x)));
544
0
    }
545
546
    friend Float16 fmax(Float16 x, Float16 y)
547
0
    {
548
0
        using std::fmax;
549
0
        return Float16(fmax(float(x), float(y)));
550
0
    }
551
552
    friend Float16 fmin(Float16 x, Float16 y)
553
0
    {
554
0
        using std::fmin;
555
0
        return Float16(fmin(float(x), float(y)));
556
0
    }
557
558
    friend Float16 hypot(Float16 x, Float16 y)
559
0
    {
560
0
        using std::hypot;
561
0
        return Float16(hypot(float(x), float(y)));
562
0
    }
563
564
    friend Float16 max(Float16 x, Float16 y)
565
0
    {
566
0
        using std::max;
567
0
        return Float16(max(float(x), float(y)));
568
0
    }
569
570
    friend Float16 min(Float16 x, Float16 y)
571
0
    {
572
0
        using std::min;
573
0
        return Float16(min(float(x), float(y)));
574
0
    }
575
576
    // Adapted from the LLVM Project, under the Apache License v2.0
577
    friend Float16 nextafter(Float16 x, Float16 y)
578
0
    {
579
0
        if (isnan(x))
580
0
            return x;
581
0
        if (isnan(y))
582
0
            return y;
583
0
        if (x == y)
584
0
            return y;
585
586
0
        std::uint16_t bits;
587
0
        if (x != Float16(0))
588
0
        {
589
0
            std::memcpy(&bits, &x.rValue, 2);
590
0
            if ((x < y) == (x > Float16(0)))
591
0
                ++bits;
592
0
            else
593
0
                --bits;
594
0
        }
595
0
        else
596
0
        {
597
0
            bits = (signbit(y) << 15) | 0x0001;
598
0
        }
599
600
0
        Float16 r;
601
0
        std::memcpy(&r.rValue, &bits, 2);
602
603
0
        return r;
604
0
    }
605
606
    friend Float16 pow(Float16 x, Float16 y)
607
0
    {
608
0
        using std::pow;
609
0
        return Float16(pow(float(x), float(y)));
610
0
    }
611
612
    friend Float16 pow(Float16 x, int n)
613
0
    {
614
0
        using std::pow;
615
0
        return Float16(pow(float(x), n));
616
0
    }
617
618
    friend Float16 round(Float16 x)
619
0
    {
620
0
        using std::round;
621
0
        return Float16(round(float(x)));
622
0
    }
623
624
    friend Float16 sqrt(Float16 x)
625
0
    {
626
0
        using std::sqrt;
627
0
        return Float16(sqrt(float(x)));
628
0
    }
629
};
630
631
template <> struct NumericLimits<Float16>
632
{
633
    static constexpr bool is_specialized = true;
634
    static constexpr bool is_signed = true;
635
    static constexpr bool is_integer = false;
636
    static constexpr bool is_exact = false;
637
    static constexpr bool has_infinity = true;
638
    static constexpr bool has_quiet_NaN = true;
639
    static constexpr bool has_signaling_NaN = true;
640
    static constexpr bool has_denorm = true;
641
    static constexpr bool is_iec559 = true;
642
643
    static constexpr int digits = 11;
644
    static constexpr int digits10 = 3;
645
    static constexpr int max_digits10 = 5;
646
    static constexpr int radix = 2;
647
648
    static constexpr Float16 epsilon()
649
0
    {
650
0
        return Float16(Float16::make_from_bits_and_value{}, 0x1400, 0.000977f);
651
0
    }
652
653
    static constexpr Float16 min()
654
0
    {
655
0
        return Float16(Float16::make_from_bits_and_value{}, 0x0001, 6.0e-8f);
656
0
    }
657
658
    static constexpr Float16 lowest()
659
0
    {
660
0
        return Float16(Float16::make_from_bits_and_value{}, 0xfbff, -65504.0f);
661
0
    }
662
663
    static constexpr Float16 max()
664
0
    {
665
0
        return Float16(Float16::make_from_bits_and_value{}, 0x7bff, +65504.0f);
666
0
    }
667
668
    static constexpr Float16 infinity()
669
0
    {
670
0
        return Float16(Float16::make_from_bits_and_value{}, 0x7c00,
671
0
                       std::numeric_limits<float>::infinity());
672
0
    }
673
674
    static constexpr Float16 quiet_NaN()
675
0
    {
676
0
        return Float16(Float16::make_from_bits_and_value{}, 0x7e00,
677
0
                       std::numeric_limits<float>::quiet_NaN());
678
0
    }
679
680
    static constexpr Float16 signaling_NaN()
681
0
    {
682
0
        return Float16(Float16::make_from_bits_and_value{}, 0xfe00,
683
0
                       std::numeric_limits<float>::signaling_NaN());
684
0
    }
685
};
686
687
//! @endcond
688
689
#endif  // #ifndef HAVE_STD_FLOAT16_T
690
691
}  // namespace cpl
692
693
#ifdef HAVE_STD_FLOAT16_T
694
using GFloat16 = std::float16_t;
695
#else
696
using GFloat16 = cpl::Float16;
697
#endif
698
699
// Define some GDAL wrappers. Their C equivalents are defined in `cpl_port.h`.
700
// (These wrappers are not necessary any more in C++, one can always
701
// call `isnan` etc directly.)
702
703
template <typename T> constexpr int CPLIsNan(T x)
704
0
{
705
    // We need to write `using std::isnan` instead of directly using
706
    // `std::isnan` because `std::isnan` only supports the types
707
    // `float` and `double`. The `isnan` for `cpl::Float16` is found in the
708
    // `cpl` namespace via argument-dependent lookup
709
    // <https://en.cppreference.com/w/cpp/language/adl>.
710
0
    using std::isnan;
711
0
    return isnan(x);
712
0
}
Unexecuted instantiation: int CPLIsNan<double>(double)
Unexecuted instantiation: int CPLIsNan<cpl::Float16>(cpl::Float16)
Unexecuted instantiation: int CPLIsNan<float>(float)
713
714
template <typename T> constexpr int CPLIsInf(T x)
715
0
{
716
0
    using std::isinf;
717
0
    return isinf(x);
718
0
}
Unexecuted instantiation: int CPLIsInf<double>(double)
Unexecuted instantiation: int CPLIsInf<cpl::Float16>(cpl::Float16)
719
720
template <typename T> constexpr int CPLIsFinite(T x)
721
{
722
    using std::isfinite;
723
    return isfinite(x);
724
}
725
726
#endif  // #ifdef __cplusplus
727
728
double CPL_DLL CPLGreatestCommonDivisor(double x, double y);
729
730
#endif  // CPL_FLOAT_H_INCLUDED