1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Copyright (C) 2016 by Southwest Research Institute (R)
5** Contact: https://www.qt.io/licensing/
6**
7** This file is part of the test suite of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:GPL-EXCEPT$
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 General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU
20** General Public License version 3 as published by the Free Software
21** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
22** included in the packaging of this file. Please review the following
23** information to ensure the GNU General Public License requirements will
24** be met: https://www.gnu.org/licenses/gpl-3.0.html.
25**
26** $QT_END_LICENSE$
27**
28****************************************************************************/
29
30#include <QtTest/QtTest>
31#include <QFloat16>
32
33#include <math.h>
34
35class tst_qfloat16: public QObject
36{
37 Q_OBJECT
38
39private slots:
40 void fuzzyCompare_data();
41 void fuzzyCompare();
42 void ltgt_data();
43 void ltgt();
44 void qNaN();
45 void infinity();
46 void float_cast();
47 void float_cast_data();
48 void promotionTests();
49 void arithOps_data();
50 void arithOps();
51 void floatToFloat16();
52 void floatFromFloat16();
53 void finite_data();
54 void finite();
55 void properties();
56 void limits();
57};
58
59void tst_qfloat16::fuzzyCompare_data()
60{
61 QTest::addColumn<qfloat16>(name: "val1");
62 QTest::addColumn<qfloat16>(name: "val2");
63 QTest::addColumn<bool>(name: "fuzEqual");
64 QTest::addColumn<bool>(name: "isEqual");
65
66 QTest::newRow(dataTag: "zero") << qfloat16(0.0f) << qfloat16(0.0f) << true << true;
67 QTest::newRow(dataTag: "ten") << qfloat16(1e1f) << qfloat16(1e1f) << true << true;
68 QTest::newRow(dataTag: "large") << qfloat16(1e4f) << qfloat16(1e4f) << true << true;
69 QTest::newRow(dataTag: "small") << qfloat16(1e-5f) << qfloat16(1e-5f) << true << true;
70 QTest::newRow(dataTag: "eps") << qfloat16(10.01f) << qfloat16(10.02f) << true << false;
71 QTest::newRow(dataTag: "eps2") << qfloat16(1024.f) << qfloat16(1033.f) << true << false;
72
73 QTest::newRow(dataTag: "mis1") << qfloat16(0.0f) << qfloat16(1.0f) << false << false;
74 QTest::newRow(dataTag: "mis2") << qfloat16(0.0f) << qfloat16(1e7f) << false << false;
75 QTest::newRow(dataTag: "mis3") << qfloat16(0.0f) << qfloat16(1e-4f) << false << false;
76 QTest::newRow(dataTag: "mis4") << qfloat16(1e8f) << qfloat16(1e-8f) << false << false;
77 QTest::newRow(dataTag: "mis5") << qfloat16(1e-4f) << qfloat16(1e-5) << false << false;
78 QTest::newRow(dataTag: "mis6") << qfloat16(1024.f) << qfloat16(1034.f) << false << false;
79}
80
81void tst_qfloat16::fuzzyCompare()
82{
83 QFETCH(qfloat16, val1);
84 QFETCH(qfloat16, val2);
85 QFETCH(bool, fuzEqual);
86 QFETCH(bool, isEqual);
87
88 if (!isEqual && (val1==val2))
89 qWarning() << "Identical arguments provided unintentionally!";
90
91 if (fuzEqual) {
92 QVERIFY(::qFuzzyCompare(val1, val2));
93 QVERIFY(::qFuzzyCompare(val2, val1));
94 QVERIFY(::qFuzzyCompare(-val1, -val2));
95 QVERIFY(::qFuzzyCompare(-val2, -val1));
96 } else {
97 QVERIFY(!::qFuzzyCompare(val1, val2));
98 QVERIFY(!::qFuzzyCompare(val2, val1));
99 QVERIFY(!::qFuzzyCompare(-val1, -val2));
100 QVERIFY(!::qFuzzyCompare(-val2, -val1));
101 }
102}
103
104void tst_qfloat16::ltgt_data()
105{
106 QTest::addColumn<float>(name: "val1");
107 QTest::addColumn<float>(name: "val2");
108
109 QTest::newRow(dataTag: "zero") << 0.0f << 0.0f;
110 QTest::newRow(dataTag: "-zero") << -0.0f << 0.0f;
111 QTest::newRow(dataTag: "ten") << 10.0f << 10.0f;
112 QTest::newRow(dataTag: "large") << 100000.0f << 100000.0f;
113 QTest::newRow(dataTag: "small") << 0.0000001f << 0.0000001f;
114 QTest::newRow(dataTag: "eps") << 10.000000000000001f << 10.00000000000002f;
115 QTest::newRow(dataTag: "eps2") << 10.000000000000001f << 10.000000000000009f;
116
117 QTest::newRow(dataTag: "mis1") << 0.0f << 1.0f;
118 QTest::newRow(dataTag: "mis2") << 0.0f << 10000000.0f;
119 QTest::newRow(dataTag: "mis3") << 0.0f << 0.0001f;
120 QTest::newRow(dataTag: "mis4") << 100000000.0f << 0.000000001f;
121 QTest::newRow(dataTag: "mis5") << 0.0001f << 0.00001f;
122
123 QTest::newRow(dataTag: "45,23") << 45.f << 23.f;
124 QTest::newRow(dataTag: "1000,76") << 1000.f << 76.f;
125}
126
127void tst_qfloat16::ltgt()
128{
129 QFETCH(float, val1);
130 QFETCH(float, val2);
131
132 QCOMPARE(qfloat16(val1) == qfloat16(val2), val1 == val2);
133 QCOMPARE(qfloat16(val1) < qfloat16(val2), val1 < val2);
134 QCOMPARE(qfloat16(val1) <= qfloat16(val2), val1 <= val2);
135 QCOMPARE(qfloat16(val1) > qfloat16(val2), val1 > val2);
136 QCOMPARE(qfloat16(val1) >= qfloat16(val2), val1 >= val2);
137
138 QCOMPARE(qfloat16(val1) == qfloat16(-val2), val1 == -val2);
139 QCOMPARE(qfloat16(val1) < qfloat16(-val2), val1 < -val2);
140 QCOMPARE(qfloat16(val1) <= qfloat16(-val2), val1 <= -val2);
141 QCOMPARE(qfloat16(val1) > qfloat16(-val2), val1 > -val2);
142 QCOMPARE(qfloat16(val1) >= qfloat16(-val2), val1 >= -val2);
143
144 QCOMPARE(qfloat16(-val1) == qfloat16(val2), -val1 == val2);
145 QCOMPARE(qfloat16(-val1) < qfloat16(val2), -val1 < val2);
146 QCOMPARE(qfloat16(-val1) <= qfloat16(val2), -val1 <= val2);
147 QCOMPARE(qfloat16(-val1) > qfloat16(val2), -val1 > val2);
148 QCOMPARE(qfloat16(-val1) >= qfloat16(val2), -val1 >= val2);
149
150 QCOMPARE(qfloat16(-val1) == qfloat16(-val2), -val1 == -val2);
151 QCOMPARE(qfloat16(-val1) < qfloat16(-val2), -val1 < -val2);
152 QCOMPARE(qfloat16(-val1) <= qfloat16(-val2), -val1 <= -val2);
153 QCOMPARE(qfloat16(-val1) > qfloat16(-val2), -val1 > -val2);
154 QCOMPARE(qfloat16(-val1) >= qfloat16(-val2), -val1 >= -val2);
155}
156
157#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ >= 404)
158 // turn -ffast-math off
159# pragma GCC optimize "no-fast-math"
160#endif
161
162void tst_qfloat16::qNaN()
163{
164#if defined __FAST_MATH__ && (__GNUC__ * 100 + __GNUC_MINOR__ < 404)
165 QSKIP("Non-conformant fast math mode is enabled, cannot run test");
166#endif
167 using Bounds = std::numeric_limits<qfloat16>;
168 const qfloat16 nan = Bounds::quiet_NaN();
169 const qfloat16 zero(0), one(1);
170 QVERIFY(!(zero > nan));
171 QVERIFY(!(zero < nan));
172 QVERIFY(!(zero == nan));
173 QVERIFY(!qIsInf(nan));
174 QVERIFY(qIsNaN(nan));
175 QVERIFY(qIsNaN(nan + one));
176 QVERIFY(qIsNaN(-nan));
177#ifdef Q_CC_INTEL
178 QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue);
179#endif
180 QVERIFY(qIsNaN(nan * zero));
181#ifdef Q_CC_INTEL
182 QEXPECT_FAIL("", "ICC optimizes zero * anything to zero", Continue);
183#endif
184 QVERIFY(qIsNaN(Bounds::infinity() * zero));
185
186 QVERIFY(!nan.isNormal());
187 QVERIFY(!qIsFinite(nan));
188 QVERIFY(!(nan == nan));
189 QCOMPARE(nan, nan); // Despite the preceding
190 QCOMPARE(qFpClassify(nan), FP_NAN);
191}
192
193void tst_qfloat16::infinity()
194{
195 const qfloat16 huge = std::numeric_limits<qfloat16>::infinity();
196 const qfloat16 zero(0), one(1), two(2);
197 QVERIFY(huge > -huge);
198 QVERIFY(huge > zero);
199 QVERIFY(-huge < zero);
200 QCOMPARE(huge, huge);
201 QCOMPARE(-huge, -huge);
202
203 // QTBUG-75812 - see overOptimized in the limits() test.
204 if (qfloat16(9.785e-4f) == qfloat16(9.794e-4f)) {
205 QCOMPARE(one / huge, zero);
206 QVERIFY(qFuzzyCompare(one / huge, zero)); // (same thing)
207 }
208
209 QVERIFY(qIsInf(huge));
210 QVERIFY(qIsInf(-huge));
211 QVERIFY(qIsInf(two * huge));
212 QVERIFY(qIsInf(huge * two));
213
214 QVERIFY(!huge.isNormal());
215 QVERIFY(!(-huge).isNormal());
216 QVERIFY(!qIsNaN(huge));
217 QVERIFY(!qIsNaN(-huge));
218 QVERIFY(!qIsFinite(huge));
219 QVERIFY(!qIsFinite(-huge));
220 QCOMPARE(qFpClassify(huge), FP_INFINITE);
221 QCOMPARE(qFpClassify(-huge), FP_INFINITE);
222}
223
224void tst_qfloat16::float_cast_data()
225{
226 QTest::addColumn<float>(name: "val");
227
228 QTest::newRow(dataTag: "zero") << 0.f;
229 QTest::newRow(dataTag: "one") << 1e0f;
230 QTest::newRow(dataTag: "ten") << 1e1f;
231 QTest::newRow(dataTag: "hund") << 1e2f;
232 QTest::newRow(dataTag: "thou") << 1e3f;
233 QTest::newRow(dataTag: "tthou") << 1e4f;
234 //QTest::newRow("hthou") << 1e5f;
235 //QTest::newRow("mil") << 1e6f;
236 //QTest::newRow("tmil") << 1e7f;
237 //QTest::newRow("hmil") << 1e8f;
238}
239
240void tst_qfloat16::float_cast()
241{
242 QFETCH(float, val);
243
244 QVERIFY(qFuzzyCompare((float)(qfloat16(val)),val));
245 QVERIFY(qFuzzyCompare((float)(qfloat16(-val)),-val));
246 QVERIFY(qFuzzyCompare((double)(qfloat16(val)),(double)(val)));
247 QVERIFY(qFuzzyCompare((double)(qfloat16(-val)),(double)(-val)));
248 //QVERIFY(qFuzzyCompare((long double)(qfloat16(val)),(long double)(val)));
249 //QVERIFY(qFuzzyCompare((long double)(qfloat16(-val)),(long double)(-val)));
250}
251
252void tst_qfloat16::promotionTests()
253{
254 QCOMPARE(sizeof(qfloat16),sizeof(qfloat16(1.f)+qfloat16(1.f)));
255 QCOMPARE(sizeof(qfloat16),sizeof(qfloat16(1.f)-qfloat16(1.f)));
256 QCOMPARE(sizeof(qfloat16),sizeof(qfloat16(1.f)*qfloat16(1.f)));
257 QCOMPARE(sizeof(qfloat16),sizeof(qfloat16(1.f)/qfloat16(1.f)));
258
259 QCOMPARE(sizeof(float),sizeof(1.f+qfloat16(1.f)));
260 QCOMPARE(sizeof(float),sizeof(1.f-qfloat16(1.f)));
261 QCOMPARE(sizeof(float),sizeof(1.f*qfloat16(1.f)));
262 QCOMPARE(sizeof(float),sizeof(1.f/qfloat16(1.f)));
263
264 QCOMPARE(sizeof(float),sizeof(qfloat16(1.f)+1.f));
265 QCOMPARE(sizeof(float),sizeof(qfloat16(1.f)-1.f));
266 QCOMPARE(sizeof(float),sizeof(qfloat16(1.f)*1.f));
267 QCOMPARE(sizeof(float),sizeof(qfloat16(1.f)/1.f));
268
269 QCOMPARE(sizeof(double),sizeof(1.+qfloat16(1.f)));
270 QCOMPARE(sizeof(double),sizeof(1.-qfloat16(1.f)));
271 QCOMPARE(sizeof(double),sizeof(1.*qfloat16(1.f)));
272 QCOMPARE(sizeof(double),sizeof(1./qfloat16(1.f)));
273
274 QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)+1.));
275 QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)-1.));
276 QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)*1.));
277 QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)/1.));
278
279 QCOMPARE(sizeof(long double),sizeof((long double)(1.)+qfloat16(1.f)));
280 QCOMPARE(sizeof(long double),sizeof((long double)(1.)-qfloat16(1.f)));
281 QCOMPARE(sizeof(long double),sizeof((long double)(1.)*qfloat16(1.f)));
282 QCOMPARE(sizeof(long double),sizeof((long double)(1.)/qfloat16(1.f)));
283
284 QCOMPARE(sizeof(long double),sizeof(qfloat16(1.f)+(long double)(1.)));
285 QCOMPARE(sizeof(long double),sizeof(qfloat16(1.f)-(long double)(1.)));
286 QCOMPARE(sizeof(long double),sizeof(qfloat16(1.f)*(long double)(1.)));
287 QCOMPARE(sizeof(long double),sizeof(qfloat16(1.f)/(long double)(1.)));
288
289 QCOMPARE(sizeof(double),sizeof(1+qfloat16(1.f)));
290 QCOMPARE(sizeof(double),sizeof(1-qfloat16(1.f)));
291 QCOMPARE(sizeof(double),sizeof(1*qfloat16(1.f)));
292 QCOMPARE(sizeof(double),sizeof(1/qfloat16(1.f)));
293
294 QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)+1));
295 QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)-1));
296 QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)*1));
297 QCOMPARE(sizeof(double),sizeof(qfloat16(1.f)/1));
298
299 QCOMPARE(QString::number(1.f),QString::number(qfloat16(1.f)));
300}
301
302void tst_qfloat16::arithOps_data()
303{
304 QTest::addColumn<float>(name: "val1");
305 QTest::addColumn<float>(name: "val2");
306
307 QTest::newRow(dataTag: "zero") << 0.0f << 2.0f;
308 QTest::newRow(dataTag: "one") << 1.0f << 4.0f;
309 QTest::newRow(dataTag: "ten") << 10.0f << 20.0f;
310}
311
312void tst_qfloat16::arithOps()
313{
314 QFETCH(float, val1);
315 QFETCH(float, val2);
316
317 QVERIFY(qFuzzyCompare(float(qfloat16(val1) + qfloat16(val2)), val1 + val2));
318 QVERIFY(qFuzzyCompare(float(qfloat16(val1) - qfloat16(val2)), val1 - val2));
319 QVERIFY(qFuzzyCompare(float(qfloat16(val1) * qfloat16(val2)), val1 * val2));
320 QVERIFY(qFuzzyCompare(float(qfloat16(val1) / qfloat16(val2)), val1 / val2));
321
322 QVERIFY(qFuzzyCompare(qfloat16(val1) + val2, val1 + val2));
323 QVERIFY(qFuzzyCompare(qfloat16(val1) - val2, val1 - val2));
324 QVERIFY(qFuzzyCompare(qfloat16(val1) * val2, val1 * val2));
325 QVERIFY(qFuzzyCompare(qfloat16(val1) / val2, val1 / val2));
326
327 QVERIFY(qFuzzyCompare(val1 + qfloat16(val2), val1 + val2));
328 QVERIFY(qFuzzyCompare(val1 - qfloat16(val2), val1 - val2));
329 QVERIFY(qFuzzyCompare(val1 * qfloat16(val2), val1 * val2));
330 QVERIFY(qFuzzyCompare(val1 / qfloat16(val2), val1 / val2));
331
332 float r1 = 0.f;
333 r1 += qfloat16(val2);
334 QVERIFY(qFuzzyCompare(r1,val2));
335
336 float r2 = 0.f;
337 r2 -= qfloat16(val2);
338 QVERIFY(qFuzzyCompare(r2,-val2));
339
340 float r3 = 1.f;
341 r3 *= qfloat16(val2);
342 QVERIFY(qFuzzyCompare(r3,val2));
343
344 float r4 = 1.f;
345 r4 /= qfloat16(val2);
346 QVERIFY(qFuzzyCompare(r4,1.f/val2));
347}
348
349void tst_qfloat16::floatToFloat16()
350{
351 float in[63];
352 qfloat16 out[63];
353 qfloat16 expected[63];
354
355 for (int i = 0; i < 63; ++i)
356 in[i] = i * (1/13.f);
357
358 for (int i = 0; i < 63; ++i)
359 expected[i] = qfloat16(in[i]);
360
361 qFloatToFloat16(out, in, length: 63);
362
363 for (int i = 0; i < 63; ++i)
364 QVERIFY(qFuzzyCompare(out[i], expected[i]));
365}
366
367void tst_qfloat16::floatFromFloat16()
368{
369 qfloat16 in[35];
370 float out[35];
371 float expected[35];
372
373 for (int i = 0; i < 35; ++i)
374 in[i] = qfloat16(i * (17.f / 3));
375
376 for (int i = 0; i < 35; ++i)
377 expected[i] = float(in[i]);
378
379 qFloatFromFloat16(out, in, length: 35);
380
381 for (int i = 0; i < 35; ++i)
382 QCOMPARE(out[i], expected[i]);
383}
384
385static qfloat16 powf16(qfloat16 base, int raise)
386{
387 const qfloat16 one(1.f);
388 if (raise < 0) {
389 raise = -raise;
390 base = one / base;
391 }
392 qfloat16 answer = (raise & 1) ? base : one;
393 while (raise > 0) {
394 raise >>= 1;
395 base *= base;
396 if (raise & 1)
397 answer *= base;
398 }
399 return answer;
400}
401
402void tst_qfloat16::finite_data()
403{
404 using Bounds = std::numeric_limits<qfloat16>;
405 QTest::addColumn<qfloat16>(name: "value");
406 QTest::addColumn<int>(name: "mode");
407
408 QTest::newRow(dataTag: "zero") << qfloat16(0) << FP_ZERO;
409 QTest::newRow(dataTag: "-zero") << -qfloat16(0) << FP_ZERO;
410 QTest::newRow(dataTag: "one") << qfloat16(1) << FP_NORMAL;
411 QTest::newRow(dataTag: "-one") << qfloat16(-1) << FP_NORMAL;
412 QTest::newRow(dataTag: "ten") << qfloat16(10) << FP_NORMAL;
413 QTest::newRow(dataTag: "-ten") << qfloat16(-10) << FP_NORMAL;
414 QTest::newRow(dataTag: "max") << Bounds::max() << FP_NORMAL;
415 QTest::newRow(dataTag: "lowest") << Bounds::lowest() << FP_NORMAL;
416 QTest::newRow(dataTag: "min") << Bounds::min() << FP_NORMAL;
417 QTest::newRow(dataTag: "-min") << -Bounds::min() << FP_NORMAL;
418 QTest::newRow(dataTag: "denorm_min") << Bounds::denorm_min() << FP_SUBNORMAL;
419 QTest::newRow(dataTag: "-denorm_min") << -Bounds::denorm_min() << FP_SUBNORMAL;
420}
421
422void tst_qfloat16::finite()
423{
424 QFETCH(qfloat16, value);
425 QFETCH(int, mode);
426 QCOMPARE(value.isNormal(), mode == FP_NORMAL);
427 QCOMPARE(value, value); // Fuzzy
428 QVERIFY(value == value); // Exact
429 QVERIFY(qIsFinite(value));
430 QVERIFY(!qIsInf(value));
431 QVERIFY(!qIsNaN(value));
432 QCOMPARE(qFpClassify(value), mode);
433
434 // *NOT* using QCOMPARE() on finite qfloat16 values, since that uses fuzzy
435 // comparison, and we need exact here.
436 const qfloat16 zero(0), plus(+1), minus(-1);
437 const qfloat16 magnitude = (value < zero) ? -value : value;
438 QVERIFY(value.copySign(plus) == magnitude);
439 QVERIFY(value.copySign(minus) == -magnitude);
440}
441
442void tst_qfloat16::properties()
443{
444 using Bounds = std::numeric_limits<qfloat16>;
445 QVERIFY(Bounds::is_specialized);
446 QVERIFY(Bounds::is_signed);
447 QVERIFY(!Bounds::is_integer);
448 QVERIFY(!Bounds::is_exact);
449 QVERIFY(Bounds::is_iec559);
450 QVERIFY(Bounds::is_bounded);
451 QVERIFY(!Bounds::is_modulo);
452 QVERIFY(!Bounds::traps);
453 QVERIFY(Bounds::has_infinity);
454 QVERIFY(Bounds::has_quiet_NaN);
455 QVERIFY(Bounds::has_signaling_NaN);
456 QCOMPARE(Bounds::has_denorm, std::denorm_present);
457 QCOMPARE(Bounds::round_style, std::round_to_nearest);
458 QCOMPARE(Bounds::radix, 2);
459 // Untested: has_denorm_loss
460}
461
462void tst_qfloat16::limits() // See also: qNaN() and infinity()
463{
464 // *NOT* using QCOMPARE() on finite qfloat16 values, since that uses fuzzy
465 // comparison, and we need exact here.
466 using Bounds = std::numeric_limits<qfloat16>;
467
468 // A few useful values:
469 const qfloat16 zero(0), one(1), ten(10);
470
471 // The specifics of minus zero:
472 // (IEEE 754 seems to want -zero < zero, but -0. == 0. and -0.f == 0.f in C++.)
473 QVERIFY(-zero <= zero);
474 QVERIFY(-zero == zero);
475 QVERIFY(!(-zero > zero));
476
477 // digits in the mantissa, including the implicit 1 before the binary dot at its left:
478 QVERIFY(qfloat16(1 << (Bounds::digits - 1)) + one > qfloat16(1 << (Bounds::digits - 1)));
479 QVERIFY(qfloat16(1 << Bounds::digits) + one == qfloat16(1 << Bounds::digits));
480
481 // There is a wilful of-by-one in how m(ax|in)_exponent are defined; they're
482 // the lowest and highest n for which radix^{n-1} are normal and finite.
483 const qfloat16 two(Bounds::radix);
484 qfloat16 bit = powf16(base: two, raise: Bounds::max_exponent - 1);
485 QVERIFY(qIsFinite(bit));
486 QVERIFY(qIsInf(bit * two));
487 bit = powf16(base: two, raise: Bounds::min_exponent - 1);
488 QVERIFY(bit.isNormal());
489 QCOMPARE(qFpClassify(bit), FP_NORMAL);
490 QVERIFY(!(bit / two).isNormal());
491 QCOMPARE(qFpClassify(bit / two), FP_SUBNORMAL);
492 QVERIFY(bit / two > zero);
493
494 // Base ten (with no matching off-by-one idiocy):
495 // the lowest negative number n such that 10^n is a valid normalized value
496 qfloat16 low10(powf16(base: ten, raise: Bounds::min_exponent10));
497 QVERIFY(low10 > zero);
498 QVERIFY(low10.isNormal());
499 low10 /= ten;
500 QVERIFY(low10 == zero || !low10.isNormal());
501 // the largest positive number n such that 10^n is a representable finite value
502 qfloat16 high10(powf16(base: ten, raise: Bounds::max_exponent10));
503 QVERIFY(high10 > zero);
504 QVERIFY(qIsFinite(high10));
505 QVERIFY(!qIsFinite(high10 * ten));
506 QCOMPARE(qFpClassify(high10), FP_NORMAL);
507
508 // How many digits are significant ? (Casts avoid linker errors ...)
509 QCOMPARE(int(Bounds::digits10), 3); // 9.79e-4 has enough sigificant digits:
510 qfloat16 below(9.785e-4f), above(9.794e-4f);
511#if 0 // Sadly, the QEMU x-compile for arm64 "optimizes" comparisons:
512 const bool overOptimized = false;
513#else
514 const bool overOptimized = (below != above);
515 if (overOptimized)
516 QEXPECT_FAIL("", "Over-optimized on ARM", Continue);
517#endif // (but it did, so should, pass everywhere else, confirming digits10 is indeed 3).
518 QVERIFY(below == above);
519 QCOMPARE(int(Bounds::max_digits10), 5); // we need 5 to distinguish these two:
520 QVERIFY(qfloat16(1000.5f) != qfloat16(1001.4f));
521
522 // Actual limiting values of the type:
523 const qfloat16 rose(one + Bounds::epsilon());
524 QVERIFY(rose > one);
525 if (overOptimized)
526 QEXPECT_FAIL("", "Over-optimized on ARM", Continue);
527 QVERIFY(one + Bounds::epsilon() / rose == one);
528
529 QVERIFY(Bounds::max() > zero);
530 QVERIFY(qIsInf(Bounds::max() * rose));
531
532 QVERIFY(Bounds::lowest() < zero);
533 QVERIFY(qIsInf(Bounds::lowest() * rose));
534
535 QVERIFY(Bounds::min() > zero);
536 QVERIFY(!(Bounds::min() / rose).isNormal());
537
538 QVERIFY(Bounds::denorm_min() > zero);
539 if (overOptimized)
540 QEXPECT_FAIL("", "Over-optimized on ARM", Continue);
541 QVERIFY(Bounds::denorm_min() / rose == zero);
542 if (overOptimized)
543 QEXPECT_FAIL("", "Over-optimized on ARM", Continue);
544 const qfloat16 under = (-Bounds::denorm_min()) / rose;
545 QVERIFY(under == -zero);
546 QCOMPARE(qfloat16(1).copySign(under), qfloat16(-1));
547}
548
549QTEST_APPLESS_MAIN(tst_qfloat16)
550#include "tst_qfloat16.moc"
551

source code of qtbase/tests/auto/corelib/global/qfloat16/tst_qfloat16.cpp