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