| 1 | /**************************************************************************** | 
|---|
| 2 | ** | 
|---|
| 3 | ** Copyright (C) 2019 The Qt Company Ltd. | 
|---|
| 4 | ** Copyright (C) 2016 by Southwest Research Institute (R) | 
|---|
| 5 | ** Contact: http://www.qt-project.org/legal | 
|---|
| 6 | ** | 
|---|
| 7 | ** This file is part of the QtCore module of the Qt Toolkit. | 
|---|
| 8 | ** | 
|---|
| 9 | ** $QT_BEGIN_LICENSE:LGPL$ | 
|---|
| 10 | ** Commercial License Usage | 
|---|
| 11 | ** Licensees holding valid commercial Qt licenses may use this file in | 
|---|
| 12 | ** accordance with the commercial license agreement provided with the | 
|---|
| 13 | ** Software or, alternatively, in accordance with the terms contained in | 
|---|
| 14 | ** a written agreement between you and The Qt Company. For licensing terms | 
|---|
| 15 | ** and conditions see https://www.qt.io/terms-conditions. For further | 
|---|
| 16 | ** information use the contact form at https://www.qt.io/contact-us. | 
|---|
| 17 | ** | 
|---|
| 18 | ** GNU Lesser General Public License Usage | 
|---|
| 19 | ** Alternatively, this file may be used under the terms of the GNU Lesser | 
|---|
| 20 | ** General Public License version 3 as published by the Free Software | 
|---|
| 21 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the | 
|---|
| 22 | ** packaging of this file. Please review the following information to | 
|---|
| 23 | ** ensure the GNU Lesser General Public License version 3 requirements | 
|---|
| 24 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. | 
|---|
| 25 | ** | 
|---|
| 26 | ** GNU General Public License Usage | 
|---|
| 27 | ** Alternatively, this file may be used under the terms of the GNU | 
|---|
| 28 | ** General Public License version 2.0 or (at your option) the GNU General | 
|---|
| 29 | ** Public license version 3 or any later version approved by the KDE Free | 
|---|
| 30 | ** Qt Foundation. The licenses are as published by the Free Software | 
|---|
| 31 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 | 
|---|
| 32 | ** included in the packaging of this file. Please review the following | 
|---|
| 33 | ** information to ensure the GNU General Public License requirements will | 
|---|
| 34 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and | 
|---|
| 35 | ** https://www.gnu.org/licenses/gpl-3.0.html. | 
|---|
| 36 | ** | 
|---|
| 37 | ** $QT_END_LICENSE$ | 
|---|
| 38 | ** | 
|---|
| 39 | ****************************************************************************/ | 
|---|
| 40 |  | 
|---|
| 41 | #ifndef QFLOAT16_H | 
|---|
| 42 | #define QFLOAT16_H | 
|---|
| 43 |  | 
|---|
| 44 | #include <QtCore/qglobal.h> | 
|---|
| 45 | #include <QtCore/qmetatype.h> | 
|---|
| 46 | #include <string.h> | 
|---|
| 47 |  | 
|---|
| 48 | #if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__AVX2__) && !defined(__F16C__) | 
|---|
| 49 | // All processors that support AVX2 do support F16C too. That doesn't mean | 
|---|
| 50 | // we're allowed to use the intrinsics directly, so we'll do it only for | 
|---|
| 51 | // the Intel and Microsoft's compilers. | 
|---|
| 52 | #  if defined(Q_CC_INTEL) || defined(Q_CC_MSVC) | 
|---|
| 53 | #    define __F16C__        1 | 
|---|
| 54 | # endif | 
|---|
| 55 | #endif | 
|---|
| 56 |  | 
|---|
| 57 | #if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__) | 
|---|
| 58 | #include <immintrin.h> | 
|---|
| 59 | #endif | 
|---|
| 60 |  | 
|---|
| 61 | QT_BEGIN_NAMESPACE | 
|---|
| 62 |  | 
|---|
| 63 | #if 0 | 
|---|
| 64 | #pragma qt_class(QFloat16) | 
|---|
| 65 | #pragma qt_no_master_include | 
|---|
| 66 | #endif | 
|---|
| 67 |  | 
|---|
| 68 | class qfloat16 | 
|---|
| 69 | { | 
|---|
| 70 | struct Wrap | 
|---|
| 71 | { | 
|---|
| 72 | // To let our private constructor work, without other code seeing | 
|---|
| 73 | // ambiguity when constructing from int, double &c. | 
|---|
| 74 | quint16 b16; | 
|---|
| 75 | constexpr inline explicit Wrap(int value) : b16(quint16(value)) {} | 
|---|
| 76 | }; | 
|---|
| 77 | public: | 
|---|
| 78 | constexpr inline qfloat16() noexcept : b16(0) {} | 
|---|
| 79 | inline qfloat16(float f) noexcept; | 
|---|
| 80 | inline operator float() const noexcept; | 
|---|
| 81 |  | 
|---|
| 82 | // Support for qIs{Inf,NaN,Finite}: | 
|---|
| 83 | bool isInf() const noexcept { return (b16 & 0x7fff) == 0x7c00; } | 
|---|
| 84 | bool isNaN() const noexcept { return (b16 & 0x7fff) > 0x7c00; } | 
|---|
| 85 | bool isFinite() const noexcept { return (b16 & 0x7fff) < 0x7c00; } | 
|---|
| 86 | Q_CORE_EXPORT int fpClassify() const noexcept; | 
|---|
| 87 | // Can't specialize std::copysign() for qfloat16 | 
|---|
| 88 | qfloat16 copySign(qfloat16 sign) const noexcept | 
|---|
| 89 | { return qfloat16(Wrap((sign.b16 & 0x8000) | (b16 & 0x7fff))); } | 
|---|
| 90 | // Support for std::numeric_limits<qfloat16> | 
|---|
| 91 | static constexpr qfloat16 _limit_epsilon()    noexcept { return qfloat16(Wrap(0x1400)); } | 
|---|
| 92 | static constexpr qfloat16 _limit_min()        noexcept { return qfloat16(Wrap(0x400)); } | 
|---|
| 93 | static constexpr qfloat16 _limit_denorm_min() noexcept { return qfloat16(Wrap(1)); } | 
|---|
| 94 | static constexpr qfloat16 _limit_max()        noexcept { return qfloat16(Wrap(0x7bff)); } | 
|---|
| 95 | static constexpr qfloat16 _limit_lowest()     noexcept { return qfloat16(Wrap(0xfbff)); } | 
|---|
| 96 | static constexpr qfloat16 _limit_infinity()   noexcept { return qfloat16(Wrap(0x7c00)); } | 
|---|
| 97 | static constexpr qfloat16 _limit_quiet_NaN()  noexcept { return qfloat16(Wrap(0x7e00)); } | 
|---|
| 98 | #if QT_CONFIG(signaling_nan) | 
|---|
| 99 | static constexpr qfloat16 _limit_signaling_NaN() noexcept { return qfloat16(Wrap(0x7d00)); } | 
|---|
| 100 | #endif | 
|---|
| 101 | inline constexpr bool isNormal() const noexcept | 
|---|
| 102 | { return (b16 & 0x7c00) && (b16 & 0x7c00) != 0x7c00; } | 
|---|
| 103 | private: | 
|---|
| 104 | quint16 b16; | 
|---|
| 105 | constexpr inline explicit qfloat16(Wrap nibble) noexcept : b16(nibble.b16) {} | 
|---|
| 106 |  | 
|---|
| 107 | Q_CORE_EXPORT static const quint32 mantissatable[]; | 
|---|
| 108 | Q_CORE_EXPORT static const quint32 exponenttable[]; | 
|---|
| 109 | Q_CORE_EXPORT static const quint32 offsettable[]; | 
|---|
| 110 | Q_CORE_EXPORT static const quint16 basetable[]; | 
|---|
| 111 | Q_CORE_EXPORT static const quint16 shifttable[]; | 
|---|
| 112 | Q_CORE_EXPORT static const quint32 roundtable[]; | 
|---|
| 113 |  | 
|---|
| 114 | friend bool qIsNull(qfloat16 f) noexcept; | 
|---|
| 115 | #if !defined(QT_NO_FLOAT16_OPERATORS) | 
|---|
| 116 | friend qfloat16 operator-(qfloat16 a) noexcept; | 
|---|
| 117 | #endif | 
|---|
| 118 | }; | 
|---|
| 119 |  | 
|---|
| 120 | Q_DECLARE_TYPEINFO(qfloat16, Q_PRIMITIVE_TYPE); | 
|---|
| 121 |  | 
|---|
| 122 | Q_CORE_EXPORT void qFloatToFloat16(qfloat16 *, const float *, qsizetype length) noexcept; | 
|---|
| 123 | Q_CORE_EXPORT void qFloatFromFloat16(float *, const qfloat16 *, qsizetype length) noexcept; | 
|---|
| 124 |  | 
|---|
| 125 | // Complement qnumeric.h: | 
|---|
| 126 | [[nodiscard]] inline bool qIsInf(qfloat16 f) noexcept { return f.isInf(); } | 
|---|
| 127 | [[nodiscard]] inline bool qIsNaN(qfloat16 f) noexcept { return f.isNaN(); } | 
|---|
| 128 | [[nodiscard]] inline bool qIsFinite(qfloat16 f) noexcept { return f.isFinite(); } | 
|---|
| 129 | [[nodiscard]] inline int qFpClassify(qfloat16 f) noexcept { return f.fpClassify(); } | 
|---|
| 130 | // [[nodiscard]] quint32 qFloatDistance(qfloat16 a, qfloat16 b); | 
|---|
| 131 |  | 
|---|
| 132 | // The remainder of these utility functions complement qglobal.h | 
|---|
| 133 | [[nodiscard]] inline int qRound(qfloat16 d) noexcept | 
|---|
| 134 | { return qRound(static_cast<float>(d)); } | 
|---|
| 135 |  | 
|---|
| 136 | [[nodiscard]] inline qint64 qRound64(qfloat16 d) noexcept | 
|---|
| 137 | { return qRound64(static_cast<float>(d)); } | 
|---|
| 138 |  | 
|---|
| 139 | [[nodiscard]] inline bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept | 
|---|
| 140 | { | 
|---|
| 141 | float f1 = static_cast<float>(p1); | 
|---|
| 142 | float f2 = static_cast<float>(p2); | 
|---|
| 143 | // The significand precision for IEEE754 half precision is | 
|---|
| 144 | // 11 bits (10 explicitly stored), or approximately 3 decimal | 
|---|
| 145 | // digits.  In selecting the fuzzy comparison factor of 102.5f | 
|---|
| 146 | // (that is, (2^10+1)/10) below, we effectively select a | 
|---|
| 147 | // window of about 1 (least significant) decimal digit about | 
|---|
| 148 | // which the two operands can vary and still return true. | 
|---|
| 149 | return (qAbs(f1 - f2) * 102.5f <= qMin(qAbs(f1), qAbs(f2))); | 
|---|
| 150 | } | 
|---|
| 151 |  | 
|---|
| 152 | [[nodiscard]] inline bool qIsNull(qfloat16 f) noexcept | 
|---|
| 153 | { | 
|---|
| 154 | return (f.b16 & static_cast<quint16>(0x7fff)) == 0; | 
|---|
| 155 | } | 
|---|
| 156 |  | 
|---|
| 157 | inline int qIntCast(qfloat16 f) noexcept | 
|---|
| 158 | { return int(static_cast<float>(f)); } | 
|---|
| 159 |  | 
|---|
| 160 | #ifndef Q_QDOC | 
|---|
| 161 | QT_WARNING_PUSH | 
|---|
| 162 | QT_WARNING_DISABLE_CLANG( "-Wc99-extensions") | 
|---|
| 163 | QT_WARNING_DISABLE_GCC( "-Wold-style-cast") | 
|---|
| 164 | inline qfloat16::qfloat16(float f) noexcept | 
|---|
| 165 | { | 
|---|
| 166 | #if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__) | 
|---|
| 167 | __m128 packsingle = _mm_set_ss(f); | 
|---|
| 168 | __m128i packhalf = _mm_cvtps_ph(packsingle, 0); | 
|---|
| 169 | b16 = _mm_extract_epi16(packhalf, 0); | 
|---|
| 170 | #elif defined (__ARM_FP16_FORMAT_IEEE) | 
|---|
| 171 | __fp16 f16 = __fp16(f); | 
|---|
| 172 | memcpy(&b16, &f16, sizeof(quint16)); | 
|---|
| 173 | #else | 
|---|
| 174 | quint32 u; | 
|---|
| 175 | memcpy(&u, &f, sizeof(quint32)); | 
|---|
| 176 | const quint32 signAndExp = u >> 23; | 
|---|
| 177 | const quint16 base = basetable[signAndExp]; | 
|---|
| 178 | const quint16 shift = shifttable[signAndExp]; | 
|---|
| 179 | const quint32 round = roundtable[signAndExp]; | 
|---|
| 180 | quint32 mantissa = (u & 0x007fffff); | 
|---|
| 181 | if ((signAndExp & 0xff) == 0xff) { | 
|---|
| 182 | if (mantissa) // keep nan from truncating to inf | 
|---|
| 183 | mantissa = qMax(1U << shift, mantissa); | 
|---|
| 184 | } else { | 
|---|
| 185 | // round half to even | 
|---|
| 186 | mantissa += round; | 
|---|
| 187 | if (mantissa & (1 << shift)) | 
|---|
| 188 | --mantissa; | 
|---|
| 189 | } | 
|---|
| 190 |  | 
|---|
| 191 | // We use add as the mantissa may overflow causing | 
|---|
| 192 | // the exp part to shift exactly one value. | 
|---|
| 193 | b16 = quint16(base + (mantissa >> shift)); | 
|---|
| 194 | #endif | 
|---|
| 195 | } | 
|---|
| 196 | QT_WARNING_POP | 
|---|
| 197 |  | 
|---|
| 198 | inline qfloat16::operator float() const noexcept | 
|---|
| 199 | { | 
|---|
| 200 | #if defined(QT_COMPILER_SUPPORTS_F16C) && defined(__F16C__) | 
|---|
| 201 | __m128i packhalf = _mm_cvtsi32_si128(b16); | 
|---|
| 202 | __m128 packsingle = _mm_cvtph_ps(packhalf); | 
|---|
| 203 | return _mm_cvtss_f32(packsingle); | 
|---|
| 204 | #elif defined (__ARM_FP16_FORMAT_IEEE) | 
|---|
| 205 | __fp16 f16; | 
|---|
| 206 | memcpy(&f16, &b16, sizeof(quint16)); | 
|---|
| 207 | return float(f16); | 
|---|
| 208 | #else | 
|---|
| 209 | quint32 u = mantissatable[offsettable[b16 >> 10] + (b16 & 0x3ff)] | 
|---|
| 210 | + exponenttable[b16 >> 10]; | 
|---|
| 211 | float f; | 
|---|
| 212 | memcpy(&f, &u, sizeof(quint32)); | 
|---|
| 213 | return f; | 
|---|
| 214 | #endif | 
|---|
| 215 | } | 
|---|
| 216 | #endif | 
|---|
| 217 |  | 
|---|
| 218 | #if !defined(QT_NO_FLOAT16_OPERATORS) | 
|---|
| 219 | inline qfloat16 operator-(qfloat16 a) noexcept | 
|---|
| 220 | { | 
|---|
| 221 | qfloat16 f; | 
|---|
| 222 | f.b16 = a.b16 ^ quint16(0x8000); | 
|---|
| 223 | return f; | 
|---|
| 224 | } | 
|---|
| 225 |  | 
|---|
| 226 | inline qfloat16 operator+(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<float>(a) + static_cast<float>(b)); } | 
|---|
| 227 | inline qfloat16 operator-(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<float>(a) - static_cast<float>(b)); } | 
|---|
| 228 | inline qfloat16 operator*(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<float>(a) * static_cast<float>(b)); } | 
|---|
| 229 | inline qfloat16 operator/(qfloat16 a, qfloat16 b) noexcept { return qfloat16(static_cast<float>(a) / static_cast<float>(b)); } | 
|---|
| 230 |  | 
|---|
| 231 | #define QF16_MAKE_ARITH_OP_FP(FP, OP) \ | 
|---|
| 232 | inline FP operator OP(qfloat16 lhs, FP rhs) noexcept { return static_cast<FP>(lhs) OP rhs; } \ | 
|---|
| 233 | inline FP operator OP(FP lhs, qfloat16 rhs) noexcept { return lhs OP static_cast<FP>(rhs); } | 
|---|
| 234 | #define QF16_MAKE_ARITH_OP_EQ_FP(FP, OP_EQ, OP) \ | 
|---|
| 235 | inline qfloat16& operator OP_EQ(qfloat16& lhs, FP rhs) noexcept \ | 
|---|
| 236 | { lhs = qfloat16(float(static_cast<FP>(lhs) OP rhs)); return lhs; } | 
|---|
| 237 | #define QF16_MAKE_ARITH_OP(FP) \ | 
|---|
| 238 | QF16_MAKE_ARITH_OP_FP(FP, +) \ | 
|---|
| 239 | QF16_MAKE_ARITH_OP_FP(FP, -) \ | 
|---|
| 240 | QF16_MAKE_ARITH_OP_FP(FP, *) \ | 
|---|
| 241 | QF16_MAKE_ARITH_OP_FP(FP, /) \ | 
|---|
| 242 | QF16_MAKE_ARITH_OP_EQ_FP(FP, +=, +) \ | 
|---|
| 243 | QF16_MAKE_ARITH_OP_EQ_FP(FP, -=, -) \ | 
|---|
| 244 | QF16_MAKE_ARITH_OP_EQ_FP(FP, *=, *) \ | 
|---|
| 245 | QF16_MAKE_ARITH_OP_EQ_FP(FP, /=, /) | 
|---|
| 246 | QF16_MAKE_ARITH_OP(long double) | 
|---|
| 247 | QF16_MAKE_ARITH_OP(double) | 
|---|
| 248 | QF16_MAKE_ARITH_OP(float) | 
|---|
| 249 | #undef QF16_MAKE_ARITH_OP | 
|---|
| 250 | #undef QF16_MAKE_ARITH_OP_FP | 
|---|
| 251 |  | 
|---|
| 252 | #define QF16_MAKE_ARITH_OP_INT(OP) \ | 
|---|
| 253 | inline double operator OP(qfloat16 lhs, int rhs) noexcept { return static_cast<double>(lhs) OP rhs; } \ | 
|---|
| 254 | inline double operator OP(int lhs, qfloat16 rhs) noexcept { return lhs OP static_cast<double>(rhs); } | 
|---|
| 255 | QF16_MAKE_ARITH_OP_INT(+) | 
|---|
| 256 | QF16_MAKE_ARITH_OP_INT(-) | 
|---|
| 257 | QF16_MAKE_ARITH_OP_INT(*) | 
|---|
| 258 | QF16_MAKE_ARITH_OP_INT(/) | 
|---|
| 259 | #undef QF16_MAKE_ARITH_OP_INT | 
|---|
| 260 |  | 
|---|
| 261 | QT_WARNING_PUSH | 
|---|
| 262 | QT_WARNING_DISABLE_FLOAT_COMPARE | 
|---|
| 263 |  | 
|---|
| 264 | inline bool operator>(qfloat16 a, qfloat16 b)  noexcept { return static_cast<float>(a) >  static_cast<float>(b); } | 
|---|
| 265 | inline bool operator<(qfloat16 a, qfloat16 b)  noexcept { return static_cast<float>(a) <  static_cast<float>(b); } | 
|---|
| 266 | inline bool operator>=(qfloat16 a, qfloat16 b) noexcept { return static_cast<float>(a) >= static_cast<float>(b); } | 
|---|
| 267 | inline bool operator<=(qfloat16 a, qfloat16 b) noexcept { return static_cast<float>(a) <= static_cast<float>(b); } | 
|---|
| 268 | inline bool operator==(qfloat16 a, qfloat16 b) noexcept { return static_cast<float>(a) == static_cast<float>(b); } | 
|---|
| 269 | inline bool operator!=(qfloat16 a, qfloat16 b) noexcept { return static_cast<float>(a) != static_cast<float>(b); } | 
|---|
| 270 |  | 
|---|
| 271 | #define QF16_MAKE_BOOL_OP_FP(FP, OP) \ | 
|---|
| 272 | inline bool operator OP(qfloat16 lhs, FP rhs) noexcept { return static_cast<FP>(lhs) OP rhs; } \ | 
|---|
| 273 | inline bool operator OP(FP lhs, qfloat16 rhs) noexcept { return lhs OP static_cast<FP>(rhs); } | 
|---|
| 274 | #define QF16_MAKE_BOOL_OP(FP) \ | 
|---|
| 275 | QF16_MAKE_BOOL_OP_FP(FP, <) \ | 
|---|
| 276 | QF16_MAKE_BOOL_OP_FP(FP, >) \ | 
|---|
| 277 | QF16_MAKE_BOOL_OP_FP(FP, >=) \ | 
|---|
| 278 | QF16_MAKE_BOOL_OP_FP(FP, <=) \ | 
|---|
| 279 | QF16_MAKE_BOOL_OP_FP(FP, ==) \ | 
|---|
| 280 | QF16_MAKE_BOOL_OP_FP(FP, !=) | 
|---|
| 281 | QF16_MAKE_BOOL_OP(long double) | 
|---|
| 282 | QF16_MAKE_BOOL_OP(double) | 
|---|
| 283 | QF16_MAKE_BOOL_OP(float) | 
|---|
| 284 | #undef QF16_MAKE_BOOL_OP | 
|---|
| 285 | #undef QF16_MAKE_BOOL_OP_FP | 
|---|
| 286 |  | 
|---|
| 287 | #define QF16_MAKE_BOOL_OP_INT(OP) \ | 
|---|
| 288 | inline bool operator OP(qfloat16 a, int b) noexcept { return static_cast<float>(a) OP static_cast<float>(b); } \ | 
|---|
| 289 | inline bool operator OP(int a, qfloat16 b) noexcept { return static_cast<float>(a) OP static_cast<float>(b); } | 
|---|
| 290 | QF16_MAKE_BOOL_OP_INT(>) | 
|---|
| 291 | QF16_MAKE_BOOL_OP_INT(<) | 
|---|
| 292 | QF16_MAKE_BOOL_OP_INT(>=) | 
|---|
| 293 | QF16_MAKE_BOOL_OP_INT(<=) | 
|---|
| 294 | QF16_MAKE_BOOL_OP_INT(==) | 
|---|
| 295 | QF16_MAKE_BOOL_OP_INT(!=) | 
|---|
| 296 | #undef QF16_MAKE_BOOL_OP_INT | 
|---|
| 297 |  | 
|---|
| 298 | QT_WARNING_POP | 
|---|
| 299 | #endif // QT_NO_FLOAT16_OPERATORS | 
|---|
| 300 |  | 
|---|
| 301 | /*! | 
|---|
| 302 | \internal | 
|---|
| 303 | */ | 
|---|
| 304 | [[nodiscard]] inline bool qFuzzyIsNull(qfloat16 f) noexcept | 
|---|
| 305 | { | 
|---|
| 306 | return qAbs(static_cast<float>(f)) <= 0.001f; | 
|---|
| 307 | } | 
|---|
| 308 |  | 
|---|
| 309 | QT_END_NAMESPACE | 
|---|
| 310 |  | 
|---|
| 311 | Q_DECLARE_METATYPE(qfloat16) | 
|---|
| 312 |  | 
|---|
| 313 | namespace std { | 
|---|
| 314 | template<> | 
|---|
| 315 | class numeric_limits<QT_PREPEND_NAMESPACE(qfloat16)> : public numeric_limits<float> | 
|---|
| 316 | { | 
|---|
| 317 | public: | 
|---|
| 318 | /* | 
|---|
| 319 | Treat quint16 b16 as if it were: | 
|---|
| 320 | uint S: 1; // b16 >> 15 (sign); can be set for zero | 
|---|
| 321 | uint E: 5; // (b16 >> 10) & 0x1f (offset exponent) | 
|---|
| 322 | uint M: 10; // b16 & 0x3ff (adjusted mantissa) | 
|---|
| 323 |  | 
|---|
| 324 | for E == 0: magnitude is M / 2.^{24} | 
|---|
| 325 | for 0 < E < 31: magnitude is (1. + M / 2.^{10}) * 2.^{E - 15) | 
|---|
| 326 | for E == 31: not finite | 
|---|
| 327 | */ | 
|---|
| 328 | static constexpr int digits = 11; | 
|---|
| 329 | static constexpr int min_exponent = -13; | 
|---|
| 330 | static constexpr int max_exponent = 16; | 
|---|
| 331 |  | 
|---|
| 332 | static constexpr int digits10 = 3; | 
|---|
| 333 | static constexpr int max_digits10 = 5; | 
|---|
| 334 | static constexpr int min_exponent10 = -4; | 
|---|
| 335 | static constexpr int max_exponent10 = 4; | 
|---|
| 336 |  | 
|---|
| 337 | static constexpr QT_PREPEND_NAMESPACE(qfloat16) epsilon() | 
|---|
| 338 | { return QT_PREPEND_NAMESPACE(qfloat16)::_limit_epsilon(); } | 
|---|
| 339 | static constexpr QT_PREPEND_NAMESPACE(qfloat16) (min)() | 
|---|
| 340 | { return QT_PREPEND_NAMESPACE(qfloat16)::_limit_min(); } | 
|---|
| 341 | static constexpr QT_PREPEND_NAMESPACE(qfloat16) denorm_min() | 
|---|
| 342 | { return QT_PREPEND_NAMESPACE(qfloat16)::_limit_denorm_min(); } | 
|---|
| 343 | static constexpr QT_PREPEND_NAMESPACE(qfloat16) (max)() | 
|---|
| 344 | { return QT_PREPEND_NAMESPACE(qfloat16)::_limit_max(); } | 
|---|
| 345 | static constexpr QT_PREPEND_NAMESPACE(qfloat16) lowest() | 
|---|
| 346 | { return QT_PREPEND_NAMESPACE(qfloat16)::_limit_lowest(); } | 
|---|
| 347 | static constexpr QT_PREPEND_NAMESPACE(qfloat16) infinity() | 
|---|
| 348 | { return QT_PREPEND_NAMESPACE(qfloat16)::_limit_infinity(); } | 
|---|
| 349 | static constexpr QT_PREPEND_NAMESPACE(qfloat16) quiet_NaN() | 
|---|
| 350 | { return QT_PREPEND_NAMESPACE(qfloat16)::_limit_quiet_NaN(); } | 
|---|
| 351 | #if QT_CONFIG(signaling_nan) | 
|---|
| 352 | static constexpr QT_PREPEND_NAMESPACE(qfloat16) signaling_NaN() | 
|---|
| 353 | { return QT_PREPEND_NAMESPACE(qfloat16)::_limit_signaling_NaN(); } | 
|---|
| 354 | #else | 
|---|
| 355 | static constexpr bool has_signaling_NaN = false; | 
|---|
| 356 | #endif | 
|---|
| 357 | }; | 
|---|
| 358 |  | 
|---|
| 359 | template<> class numeric_limits<const QT_PREPEND_NAMESPACE(qfloat16)> | 
|---|
| 360 | : public numeric_limits<QT_PREPEND_NAMESPACE(qfloat16)> {}; | 
|---|
| 361 | template<> class numeric_limits<volatile QT_PREPEND_NAMESPACE(qfloat16)> | 
|---|
| 362 | : public numeric_limits<QT_PREPEND_NAMESPACE(qfloat16)> {}; | 
|---|
| 363 | template<> class numeric_limits<const volatile QT_PREPEND_NAMESPACE(qfloat16)> | 
|---|
| 364 | : public numeric_limits<QT_PREPEND_NAMESPACE(qfloat16)> {}; | 
|---|
| 365 |  | 
|---|
| 366 | // Adding overloads to std isn't allowed, so we can't extend this to support | 
|---|
| 367 | // for fpclassify(), isnormal() &c. (which, furthermore, are macros on MinGW). | 
|---|
| 368 | } // namespace std | 
|---|
| 369 |  | 
|---|
| 370 | #endif // QFLOAT16_H | 
|---|
| 371 |  | 
|---|