/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 |