Coverage Report

Created: 2025-06-13 06:29

/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
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
0
        : rValue(repr(fValue))
115
0
    {
116
0
    }
117
118
    static constexpr repr computeToRepr(compute fValue)
119
0
    {
120
0
        return fValue;
121
0
    }
122
123
    static constexpr compute reprToCompute(repr rValue)
124
0
    {
125
0
        return rValue;
126
0
    }
127
128
    template <typename T> static constexpr repr toRepr(T fValue)
129
0
    {
130
0
        return static_cast<repr>(fValue);
131
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_
132
133
    template <typename T> static constexpr T fromRepr(repr rValue)
134
0
    {
135
0
        return static_cast<T>(rValue);
136
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_
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
    constexpr Float16(make_from_bits_and_value, std::uint16_t bits,
151
                      CPL_UNUSED float fValue)
152
        : rValue(bits)
153
    {
154
    }
155
156
    static unsigned float2unsigned(float f)
157
    {
158
        unsigned u;
159
        std::memcpy(&u, &f, 4);
160
        return u;
161
    }
162
163
    static float unsigned2float(unsigned u)
164
    {
165
        float f;
166
        std::memcpy(&f, &u, 4);
167
        return f;
168
    }
169
170
    // Copied from cpl_float.cpp so that we can inline for performance
171
    static std::uint16_t computeToRepr(float fFloat32)
172
    {
173
        std::uint32_t iFloat32 = float2unsigned(fFloat32);
174
175
        std::uint32_t iSign = (iFloat32 >> 31) & 0x00000001;
176
        std::uint32_t iExponent = (iFloat32 >> 23) & 0x000000ff;
177
        std::uint32_t iMantissa = iFloat32 & 0x007fffff;
178
179
        if (iExponent == 255)
180
        {
181
            if (iMantissa == 0)
182
            {
183
                // Positive or negative infinity.
184
                return static_cast<std::int16_t>((iSign << 15) | 0x7C00);
185
            }
186
187
            // NaN -- preserve sign and significand bits.
188
            if (iMantissa >> 13)
189
                return static_cast<std::int16_t>((iSign << 15) | 0x7C00 |
190
                                                 (iMantissa >> 13));
191
            return static_cast<std::int16_t>((iSign << 15) | 0x7E00);
192
        }
193
194
        if (iExponent <= 127 - 15)
195
        {
196
            // Zero, float32 denormalized number or float32 too small normalized
197
            // number
198
            if (13 + 1 + 127 - 15 - iExponent >= 32)
199
                return static_cast<std::int16_t>(iSign << 15);
200
201
            // Return a denormalized number
202
            return static_cast<std::int16_t>(
203
                (iSign << 15) |
204
                ((iMantissa | 0x00800000) >> (13 + 1 + 127 - 15 - iExponent)));
205
        }
206
207
        if (iExponent - (127 - 15) >= 31)
208
        {
209
            return static_cast<std::int16_t>((iSign << 15) |
210
                                             0x7C00);  // Infinity
211
        }
212
213
        // Normalized number.
214
        iExponent = iExponent - (127 - 15);
215
        iMantissa = iMantissa >> 13;
216
217
        // Assemble sign, exponent and mantissa.
218
        // coverity[overflow_sink]
219
        return static_cast<std::int16_t>((iSign << 15) | (iExponent << 10) |
220
                                         iMantissa);
221
    }
222
223
    // Copied from cpl_float.cpp so that we can inline for performance
224
    static float reprToCompute(std::uint16_t iHalf)
225
    {
226
        std::uint32_t iSign = (iHalf >> 15) & 0x00000001;
227
        int iExponent = (iHalf >> 10) & 0x0000001f;
228
        std::uint32_t iMantissa = iHalf & 0x000003ff;
229
230
        if (iExponent == 31)
231
        {
232
            if (iMantissa == 0)
233
            {
234
                // Positive or negative infinity.
235
                return unsigned2float((iSign << 31) | 0x7f800000);
236
            }
237
238
            // NaN -- preserve sign and significand bits.
239
            return unsigned2float((iSign << 31) | 0x7f800000 |
240
                                  (iMantissa << 13));
241
        }
242
243
        if (iExponent == 0)
244
        {
245
            if (iMantissa == 0)
246
            {
247
                // Plus or minus zero.
248
                return unsigned2float(iSign << 31);
249
            }
250
251
            // Denormalized number -- renormalize it.
252
            while (!(iMantissa & 0x00000400))
253
            {
254
                iMantissa <<= 1;
255
                iExponent -= 1;
256
            }
257
258
            iExponent += 1;
259
            iMantissa &= ~0x00000400U;
260
        }
261
262
        // Normalized number.
263
        iExponent = iExponent + (127 - 15);
264
        iMantissa = iMantissa << 13;
265
266
        // Assemble sign, exponent and mantissa.
267
        /* coverity[overflow_sink] */
268
        return unsigned2float((iSign << 31) |
269
                              (static_cast<std::uint32_t>(iExponent) << 23) |
270
                              iMantissa);
271
    }
272
273
    template <typename T> static repr toRepr(T fValue)
274
    {
275
        return computeToRepr(static_cast<compute>(fValue));
276
    }
277
278
    template <typename T> static T fromRepr(repr rValue)
279
    {
280
        return static_cast<T>(reprToCompute(rValue));
281
    }
282
283
#endif  // #ifndef HAVE__FLOAT16
284
285
  private:
286
    repr rValue;
287
288
  public:
289
    compute get() const
290
0
    {
291
0
        return reprToCompute(rValue);
292
0
    }
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
0
    constexpr Float16(_Float16 hfValue) : rValue(hfValue)
306
0
    {
307
0
    }
308
309
    constexpr operator _Float16() const
310
0
    {
311
0
        return rValue;
312
0
    }
313
#endif
314
315
    // cppcheck-suppress-macro noExplicitConstructor
316
#define GDAL_DEFINE_CONVERSION(TYPE)                                           \
317
                                                                               \
318
0
    Float16(TYPE fValue) : rValue(toRepr(fValue))                              \
319
0
    {                                                                          \
320
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)
321
                                                                               \
322
    operator TYPE() const                                                      \
323
0
    {                                                                          \
324
0
        return fromRepr<TYPE>(rValue);                                         \
325
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
326
327
    GDAL_DEFINE_CONVERSION(float)
328
    GDAL_DEFINE_CONVERSION(double)
329
    GDAL_DEFINE_CONVERSION(char)
330
    GDAL_DEFINE_CONVERSION(signed char)
331
    GDAL_DEFINE_CONVERSION(short)
332
    GDAL_DEFINE_CONVERSION(int)
333
    GDAL_DEFINE_CONVERSION(long)
334
    GDAL_DEFINE_CONVERSION(long long)
335
    GDAL_DEFINE_CONVERSION(unsigned char)
336
    GDAL_DEFINE_CONVERSION(unsigned short)
337
    GDAL_DEFINE_CONVERSION(unsigned int)
338
    GDAL_DEFINE_CONVERSION(unsigned long)
339
    GDAL_DEFINE_CONVERSION(unsigned long long)
340
341
#undef GDAL_DEFINE_CONVERSION
342
343
    // Arithmetic operators
344
345
    friend Float16 operator+(Float16 x)
346
0
    {
347
0
        return +x.get();
348
0
    }
349
350
    friend Float16 operator-(Float16 x)
351
0
    {
352
0
        return -x.get();
353
0
    }
354
355
#define GDAL_DEFINE_ARITHOP(OP)                                                \
356
                                                                               \
357
    friend Float16 operator OP(Float16 x, Float16 y)                           \
358
0
    {                                                                          \
359
0
        return x.get() OP y.get();                                             \
360
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)
361
                                                                               \
362
    friend double operator OP(double x, Float16 y)                             \
363
0
    {                                                                          \
364
0
        return x OP y.get();                                                   \
365
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)
366
                                                                               \
367
    friend float operator OP(float x, Float16 y)                               \
368
0
    {                                                                          \
369
0
        return x OP y.get();                                                   \
370
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)
371
                                                                               \
372
    friend Float16 operator OP(int x, Float16 y)                               \
373
0
    {                                                                          \
374
0
        return x OP y.get();                                                   \
375
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)
376
                                                                               \
377
    friend double operator OP(Float16 x, double y)                             \
378
0
    {                                                                          \
379
0
        return x.get() OP y;                                                   \
380
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)
381
                                                                               \
382
    friend float operator OP(Float16 x, float y)                               \
383
0
    {                                                                          \
384
0
        return x.get() OP y;                                                   \
385
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)
386
                                                                               \
387
    friend Float16 operator OP(Float16 x, int y)                               \
388
0
    {                                                                          \
389
0
        return x.get() OP y;                                                   \
390
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)
391
392
    GDAL_DEFINE_ARITHOP(+)
393
    GDAL_DEFINE_ARITHOP(-)
394
    GDAL_DEFINE_ARITHOP(*)
395
    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
0
    {                                                                          \
405
0
        return x.get() OP y.get();                                             \
406
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)
407
                                                                               \
408
    friend bool operator OP(float x, Float16 y)                                \
409
0
    {                                                                          \
410
0
        return x OP y.get();                                                   \
411
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)
412
                                                                               \
413
    friend bool operator OP(double x, Float16 y)                               \
414
0
    {                                                                          \
415
0
        return x OP y.get();                                                   \
416
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)
417
                                                                               \
418
    friend bool operator OP(int x, Float16 y)                                  \
419
0
    {                                                                          \
420
0
        return x OP y.get();                                                   \
421
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)
422
                                                                               \
423
    friend bool operator OP(Float16 x, float y)                                \
424
0
    {                                                                          \
425
0
        return x.get() OP y;                                                   \
426
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)
427
                                                                               \
428
    friend bool operator OP(Float16 x, double y)                               \
429
0
    {                                                                          \
430
0
        return x.get() OP y;                                                   \
431
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)
432
                                                                               \
433
    friend bool operator OP(Float16 x, int y)                                  \
434
0
    {                                                                          \
435
0
        return x.get() OP y;                                                   \
436
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)
437
438
    GDAL_DEFINE_COMPARISON(==)
439
    GDAL_DEFINE_COMPARISON(!=)
440
    GDAL_DEFINE_COMPARISON(<)
441
    GDAL_DEFINE_COMPARISON(>)
442
    GDAL_DEFINE_COMPARISON(<=)
443
    GDAL_DEFINE_COMPARISON(>=)
444
445
#undef GDAL_DEFINE_COMPARISON
446
447
    // Standard math functions
448
449
    friend bool isfinite(Float16 x)
450
0
    {
451
0
        using std::isfinite;
452
0
        return isfinite(float(x));
453
0
    }
454
455
    friend bool isinf(Float16 x)
456
0
    {
457
0
        using std::isinf;
458
0
        return isinf(float(x));
459
0
    }
460
461
    friend bool isnan(Float16 x)
462
0
    {
463
0
        using std::isnan;
464
0
        return isnan(float(x));
465
0
    }
466
467
    friend bool isnormal(Float16 x)
468
0
    {
469
0
        using std::isnormal;
470
0
        return isnormal(float(x));
471
0
    }
472
473
    friend bool signbit(Float16 x)
474
0
    {
475
0
        using std::signbit;
476
0
        return signbit(float(x));
477
0
    }
478
479
    friend Float16 abs(Float16 x)
480
0
    {
481
0
        using std::abs;
482
0
        return Float16(abs(float(x)));
483
0
    }
484
485
    friend Float16 cbrt(Float16 x)
486
0
    {
487
0
        using std::cbrt;
488
0
        return Float16(cbrt(float(x)));
489
0
    }
490
491
    friend Float16 ceil(Float16 x)
492
0
    {
493
0
        using std::ceil;
494
0
        return Float16(ceil(float(x)));
495
0
    }
496
497
    friend Float16 copysign(Float16 x, Float16 y)
498
0
    {
499
0
        using std::copysign;
500
0
        return Float16(copysign(float(x), float(y)));
501
0
    }
502
503
    friend Float16 fabs(Float16 x)
504
0
    {
505
0
        using std::fabs;
506
0
        return Float16(fabs(float(x)));
507
0
    }
508
509
    friend Float16 floor(Float16 x)
510
0
    {
511
0
        using std::floor;
512
0
        return Float16(floor(float(x)));
513
0
    }
514
515
    friend Float16 fmax(Float16 x, Float16 y)
516
0
    {
517
0
        using std::fmax;
518
0
        return Float16(fmax(float(x), float(y)));
519
0
    }
520
521
    friend Float16 fmin(Float16 x, Float16 y)
522
0
    {
523
0
        using std::fmin;
524
0
        return Float16(fmin(float(x), float(y)));
525
0
    }
526
527
    friend Float16 hypot(Float16 x, Float16 y)
528
0
    {
529
0
        using std::hypot;
530
0
        return Float16(hypot(float(x), float(y)));
531
0
    }
532
533
    friend Float16 max(Float16 x, Float16 y)
534
0
    {
535
0
        using std::max;
536
0
        return Float16(max(float(x), float(y)));
537
0
    }
538
539
    friend Float16 min(Float16 x, Float16 y)
540
0
    {
541
0
        using std::min;
542
0
        return Float16(min(float(x), float(y)));
543
0
    }
544
545
    // Adapted from the LLVM Project, under the Apache License v2.0
546
    friend Float16 nextafter(Float16 x, Float16 y)
547
0
    {
548
0
        if (isnan(x))
549
0
            return x;
550
0
        if (isnan(y))
551
0
            return y;
552
0
        if (x == y)
553
0
            return y;
554
555
0
        std::uint16_t bits;
556
0
        if (x != Float16(0))
557
0
        {
558
0
            std::memcpy(&bits, &x.rValue, 2);
559
0
            if ((x < y) == (x > Float16(0)))
560
0
                ++bits;
561
0
            else
562
0
                --bits;
563
0
        }
564
0
        else
565
0
        {
566
0
            bits = (signbit(y) << 15) | 0x0001;
567
0
        }
568
569
0
        Float16 r;
570
0
        std::memcpy(&r.rValue, &bits, 2);
571
572
0
        return r;
573
0
    }
574
575
    friend Float16 pow(Float16 x, Float16 y)
576
0
    {
577
0
        using std::pow;
578
0
        return Float16(pow(float(x), float(y)));
579
0
    }
580
581
    friend Float16 pow(Float16 x, int n)
582
0
    {
583
0
        using std::pow;
584
0
        return Float16(pow(float(x), n));
585
0
    }
586
587
    friend Float16 round(Float16 x)
588
0
    {
589
0
        using std::round;
590
0
        return Float16(round(float(x)));
591
0
    }
592
593
    friend Float16 sqrt(Float16 x)
594
0
    {
595
0
        using std::sqrt;
596
0
        return Float16(sqrt(float(x)));
597
0
    }
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
    static constexpr Float16 epsilon()
618
0
    {
619
0
        return Float16(Float16::make_from_bits_and_value{}, 0x1400, 0.000977f);
620
0
    }
621
622
    static constexpr Float16 min()
623
0
    {
624
0
        return Float16(Float16::make_from_bits_and_value{}, 0x0001, 6.0e-8f);
625
0
    }
626
627
    static constexpr Float16 lowest()
628
0
    {
629
0
        return Float16(Float16::make_from_bits_and_value{}, 0xfbff, -65504.0f);
630
0
    }
631
632
    static constexpr Float16 max()
633
0
    {
634
0
        return Float16(Float16::make_from_bits_and_value{}, 0x7bff, +65504.0f);
635
0
    }
636
637
    static constexpr Float16 infinity()
638
0
    {
639
0
        return Float16(Float16::make_from_bits_and_value{}, 0x7c00,
640
0
                       std::numeric_limits<float>::infinity());
641
0
    }
642
643
    static constexpr Float16 quiet_NaN()
644
0
    {
645
0
        return Float16(Float16::make_from_bits_and_value{}, 0x7e00,
646
0
                       std::numeric_limits<float>::quiet_NaN());
647
0
    }
648
649
    static constexpr Float16 signaling_NaN()
650
0
    {
651
0
        return Float16(Float16::make_from_bits_and_value{}, 0xfe00,
652
0
                       std::numeric_limits<float>::signaling_NaN());
653
0
    }
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
template <typename T> constexpr int CPLIsNan(T x)
673
0
{
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
0
    using std::isnan;
680
0
    return isnan(x);
681
0
}
Unexecuted instantiation: int CPLIsNan<double>(double)
Unexecuted instantiation: int CPLIsNan<cpl::Float16>(cpl::Float16)
Unexecuted instantiation: int CPLIsNan<float>(float)
682
683
template <typename T> constexpr int CPLIsInf(T x)
684
0
{
685
0
    using std::isinf;
686
0
    return isinf(x);
687
0
}
Unexecuted instantiation: int CPLIsInf<double>(double)
Unexecuted instantiation: int CPLIsInf<cpl::Float16>(cpl::Float16)
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