blob: 302b3286033f4e68e3c7d11ebc3071af2b7d7c08 [file] [log] [blame]
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001/* ==========================================================================
2 * float_tests.c -- tests for float and conversion to/from half-precision
3 *
Laurence Lundblade492be182025-08-09 09:45:34 -07004 * Copyright (c) 2018-2025, Laurence Lundblade. All rights reserved.
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07005 * Copyright (c) 2021, Arm Limited. All rights reserved.
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
Laurence Lundbladee8f58162024-08-22 10:30:08 -07009 * See BSD-3-Clause license in file named "LICENSE"
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070010 *
11 * Created on 9/19/18
12 * ========================================================================= */
Laurence Lundblade68a13352018-09-23 02:19:54 -070013
Laurence Lundblade2aa0b572020-07-16 19:48:42 -070014
15#include "float_tests.h"
Laurence Lundblade7596eef2024-12-21 10:08:32 -070016#include "qcbor/qcbor_main_encode.h"
17#include "qcbor/qcbor_number_encode.h"
Laurence Lundblade02fcf312020-07-17 02:49:46 -070018#include "qcbor/qcbor_decode.h"
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -070019#include "qcbor/qcbor_spiffy_decode.h"
Laurence Lundblade33ed26f2024-11-24 10:26:43 -080020#include "qcbor/qcbor_number_decode.h"
Laurence Lundblade492be182025-08-09 09:45:34 -070021#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070022#include <math.h> /* For INFINITY and NAN and isnan() */
Laurence Lundblade492be182025-08-09 09:45:34 -070023#endif
Laurence Lundblade585127a2020-07-15 03:25:24 -070024
Laurence Lundblade16a207a2021-09-18 17:22:46 -070025
Laurence Lundblade492be182025-08-09 09:45:34 -070026/* This is off because it is affected by varying behavior of CPUs,
27 * compilers and float libraries. Particularly the qNaN bit
28 */
29//#define QCBOR_COMPARE_TO_HW_CONVERSION
30
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070031
32/* Make a test results code that includes three components. Return code
33 * is xxxyyyzzz where zz is the error code, yy is the test number and
34 * zz is check being performed
Laurence Lundblade16a207a2021-09-18 17:22:46 -070035 */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070036static inline int32_t
37MakeTestResultCode(uint32_t uTestCase,
38 uint32_t uTestNumber,
39 QCBORError uErrorCode)
Laurence Lundblade16a207a2021-09-18 17:22:46 -070040{
41 uint32_t uCode = (uTestCase * 1000000) +
42 (uTestNumber * 1000) +
43 (uint32_t)uErrorCode;
44 return (int32_t)uCode;
45}
46
47
Laurence Lundbladed711fb22018-09-26 14:35:22 -070048#include "half_to_double_from_rfc7049.h"
Laurence Lundblade68a13352018-09-23 02:19:54 -070049
Laurence Lundblade2d85ce42018-10-12 14:12:47 +080050
Laurence Lundblade492be182025-08-09 09:45:34 -070051#ifndef USEFULBUF_DISABLE_ALL_FLOAT
52
53
54/* ----- Half Precsion ----------- */
55#define HALF_NUM_SIGNIFICAND_BITS (10)
56#define HALF_NUM_EXPONENT_BITS (5)
57#define HALF_NUM_SIGN_BITS (1)
58
59#define HALF_SIGNIFICAND_SHIFT (0)
60#define HALF_EXPONENT_SHIFT (HALF_NUM_SIGNIFICAND_BITS)
61#define HALF_SIGN_SHIFT (HALF_NUM_SIGNIFICAND_BITS + HALF_NUM_EXPONENT_BITS)
62
63#define HALF_SIGNIFICAND_MASK (0x3ffU) // The lower 10 bits
64#define HALF_EXPONENT_MASK (0x1fU << HALF_EXPONENT_SHIFT) // 0x7c00 5 bits of exponent
65#define HALF_SIGN_MASK (0x01U << HALF_SIGN_SHIFT) // 0x8000 1 bit of sign
66#define HALF_QUIET_NAN_BIT (0x01U << (HALF_NUM_SIGNIFICAND_BITS-1)) // 0x0200
67
68/* Biased Biased Unbiased Use
69 * 0x00 0 -15 0 and subnormal
70 * 0x01 1 -14 Smallest normal exponent
71 * 0x1e 30 15 Largest normal exponent
72 * 0x1F 31 16 NaN and Infinity */
73#define HALF_EXPONENT_BIAS (15)
74#define HALF_EXPONENT_MAX (HALF_EXPONENT_BIAS) // 15 Unbiased
75#define HALF_EXPONENT_MIN (-HALF_EXPONENT_BIAS+1) // -14 Unbiased
76#define HALF_EXPONENT_ZERO (-HALF_EXPONENT_BIAS) // -15 Unbiased
77#define HALF_EXPONENT_INF_OR_NAN (HALF_EXPONENT_BIAS+1) // 16 Unbiased
78
79
80/* ------ Single-Precision -------- */
81#define SINGLE_NUM_SIGNIFICAND_BITS (23)
82#define SINGLE_NUM_EXPONENT_BITS (8)
83#define SINGLE_NUM_SIGN_BITS (1)
84
85#define SINGLE_SIGNIFICAND_SHIFT (0)
86#define SINGLE_EXPONENT_SHIFT (SINGLE_NUM_SIGNIFICAND_BITS)
87#define SINGLE_SIGN_SHIFT (SINGLE_NUM_SIGNIFICAND_BITS + SINGLE_NUM_EXPONENT_BITS)
88
89#define SINGLE_SIGNIFICAND_MASK (0x7fffffU) // The lower 23 bits
90#define SINGLE_EXPONENT_MASK (0xffU << SINGLE_EXPONENT_SHIFT) // 8 bits of exponent
91#define SINGLE_SIGN_MASK (0x01U << SINGLE_SIGN_SHIFT) // 1 bit of sign
92#define SINGLE_QUIET_NAN_BIT (0x01U << (SINGLE_NUM_SIGNIFICAND_BITS-1))
93
94/* Biased Biased Unbiased Use
95 * 0x0000 0 -127 0 and subnormal
96 * 0x0001 1 -126 Smallest normal exponent
97 * 0x7f 127 0 1
98 * 0xfe 254 127 Largest normal exponent
99 * 0xff 255 128 NaN and Infinity */
100#define SINGLE_EXPONENT_BIAS (127)
101#define SINGLE_EXPONENT_MAX (SINGLE_EXPONENT_BIAS)
102#define SINGLE_EXPONENT_MIN (-SINGLE_EXPONENT_BIAS+1)
103#define SINGLE_EXPONENT_ZERO (-SINGLE_EXPONENT_BIAS)
104#define SINGLE_EXPONENT_INF_OR_NAN (SINGLE_EXPONENT_BIAS+1)
105
106#define SINGLE_NAN_BITS SINGLE_EXPONENT_MASK /* NAN bits except payload */
107#define SINGLE_QNAN 0x400000
108#define SINGLE_SNAN 0x000000
109
110
111/* --------- Double-Precision ---------- */
112#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
113#define DOUBLE_NUM_EXPONENT_BITS (11)
114#define DOUBLE_NUM_SIGN_BITS (1)
115
116#define DOUBLE_SIGNIFICAND_SHIFT (0)
117#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS)
118#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
119
120#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits
121#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
122#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
123#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
124
125
126/* Biased Biased Unbiased Use
127 * 0x00000000 0 -1023 0 and subnormal
128 * 0x00000001 1 -1022 Smallest normal exponent
129 * 0x000007fe 2046 1023 Largest normal exponent
130 * 0x000007ff 2047 1024 NaN and Infinity */
131#define DOUBLE_EXPONENT_BIAS (1023)
132#define DOUBLE_EXPONENT_MAX (DOUBLE_EXPONENT_BIAS)
133#define DOUBLE_EXPONENT_MIN (-DOUBLE_EXPONENT_BIAS+1)
134#define DOUBLE_EXPONENT_ZERO (-DOUBLE_EXPONENT_BIAS)
135#define DOUBLE_EXPONENT_INF_OR_NAN (DOUBLE_EXPONENT_BIAS+1)
136
137#define DOUBLE_NAN_BITS DOUBLE_EXPONENT_MASK /* NAN bits except payload */
138#define DOUBLE_QNAN 0x8000000000000ULL
139#define DOUBLE_SNAN 0x0000000000000ULL
140
141
142
143#ifdef NAN_EXPERIMENT
144#include <stdlib.h>
145#include <stdio.h>
146
147 int
148NaNExperiments(void)
149{
150 // double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
151 // double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
152 // double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
153
154
155 for(int i = 999; i < 1000; i++) {
156 uint64_t x1 = (uint64_t)rand() % SINGLE_SIGNIFICAND_MASK;
157
158 uint64_t uDub = DOUBLE_EXPONENT_MASK | (x1 << (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS));
159
160 double dd = UsefulBufUtil_CopyUint64ToDouble(uDub);
161
162 float ff = (float)dd;
163
164 uint32_t uu = UsefulBufUtil_CopyFloatToUint32(ff);
165
166 uint64_t x2 = uu & SINGLE_SIGNIFICAND_MASK;
167
168 if(x2 != x1) {
169 printf("%d: %llx %llx %llx %llx\n", i, x1, x2, x1 ^ x2, x1 & 0x200000);
170 }
171 }
172
173#if 0
174 float f1 = (float)dqNaN;
175 float f2 = (float)dsNaN;
176 float f3 = (float)dqNaNPayload;
177
178
179 uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
180 uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
181 uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
182
183 // Result of this on x86 is that every NaN is a qNaN. The intel
184 // CVTSD2SS instruction ignores the NaN payload and even converts
185 // a sNaN to a qNaN.
186#endif
187
188 return 0;
189}
190#endif /* NAN_EXPERIMENT */
191
192
193/* Returns 0 if OK, 1 if not */
194static int32_t
195HWCheckFloatToDouble(const uint64_t uDoubleToConvert, uint32_t uExpectedSingle)
196{
197#ifdef QCBOR_COMPARE_TO_HW_CONVERSION
198 if(uExpectedSingle) {
199 /* This test is off by default. It's purpose is to check
200 * QCBOR's mask-n-shift implementation against the HW/CPU
201 * instructions that do conversion between double and single.
202 * It is off because it is only used on occasion to verify
203 * QCBOR and because it is suspected that some HW/CPU does
204 * not implement this correctly. NaN payloads are an obscure
205 * feature. */
206 float f;
207 double d;
208 uint32_t uSingle;
209
210 d = UsefulBufUtil_CopyUint64ToDouble(uDoubleToConvert);
211
212 f = (float)d;
213
214 uSingle = UsefulBufUtil_CopyFloatToUint32(f);
215
216 if(isnan(d)) {
217 /* Some (all?) Intel CPUs always set the qNaN bit in conversion */
218 uExpectedSingle |= SINGLE_QNAN;
219 }
220
221 if(uSingle != uExpectedSingle) {
222 return 1;
223 }
224 }
225#else
226 (void)uDoubleToConvert;
227 (void)uExpectedSingle;
228#endif /* QCBOR_COMPARE_TO_HW_CONVERSION */
229
230 return 0;
231}
232
233/* Returns 0 if OK, 1 if not */
234static int32_t
235HWCheckDoubleToFloat(const uint32_t uSingleToConvert, uint64_t uExpectedDouble)
236{
237#ifdef QCBOR_COMPARE_TO_HW_CONVERSION
238 if(uExpectedDouble) {
239 /* This test is off by default. It's purpose is to check
240 * QCBOR's mask-n-shift implementation against the HW/CPU
241 * instructions that do conversion between double and single.
242 * It is off because it is only used on occasion to verify
243 * QCBOR and because it is suspected that some HW/CPU does
244 * not implement this correctly. NaN payloads are an obscure
245 * feature. */
246 float f;
247 double d2;
248 uint64_t dd;
249
250 f = UsefulBufUtil_CopyUint32ToFloat(uSingleToConvert);
251
252 d2 = (double)f;
253
254 dd = UsefulBufUtil_CopyDoubleToUint64(d2);
255
256 if(isnan(f)) {
257 /* Some (all?) Intel CPUs always set the qNaN bit in conversion */
258 uExpectedDouble |= DOUBLE_QNAN;
259 }
260
261 if(dd != uExpectedDouble ) {
262 return 1;
263 }
264 }
265#else
266 (void)uSingleToConvert;
267 (void)uExpectedDouble;
268#endif /* QCBOR_COMPARE_TO_HW_CONVERSION */
269 return 0;
270}
271
272
273#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
274/* Returns 0 if OK, 1 if not */
275static int32_t
276CompareToCarsten(const uint64_t uDouble, const UsefulBufC TestOutput, const UsefulBufC Expected)
277{
278 if(Expected.len == 3) {
279 /* Just works for double to half now */
280 int uFloat16 = try_float16_encode(uDouble);
281 uint8_t CarstenEncoded[3];
282 CarstenEncoded[0] = 0xf9;
283 CarstenEncoded[1] = (uFloat16 & 0xff00) >> 8;
284 CarstenEncoded[2] = uFloat16 & 0xff;
285
286 UsefulBufC CarstenEncodedUB;
287 CarstenEncodedUB.len = 3;
288 CarstenEncodedUB.ptr = CarstenEncoded;
289
290 if(UsefulBuf_Compare(TestOutput, CarstenEncodedUB)) {
291 return 1;
292 }
293 }
294
295 return 0;
296}
297#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
298
299
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800300struct FloatTestCase {
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700301 double dNumber;
Laurence Lundblade492be182025-08-09 09:45:34 -0700302 float fNumber; /* Only used when preferred is disabled */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700303 UsefulBufC Preferred;
304 UsefulBufC NotPreferred;
305 UsefulBufC CDE;
306 UsefulBufC DCBOR;
307};
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700308
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800309/* Boundaries for destination conversions:
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700310 *
311 * smallest subnormal single 1.401298464324817e-45 2^^-149
312 * largest subnormal single 1.1754942106924411e-38 2^^-126
313 * smallest normal single 1.1754943508222875e-38
314 * largest single 3.4028234663852886E+38
315 *
316 * smallest subnormal half 5.9604644775390625E-8
317 * largest subnormal half 6.097555160522461E-5
318 * smallest normal half 6.103515625E-5
319 * largest half 65504.0
320 *
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800321 * Boundaries for origin conversions:
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700322 * smallest subnormal double 5.0e-324 2^^-1074
323 * largest subnormal double
324 * smallest normal double 2.2250738585072014e-308 2^^-1022
325 * largest normal double 1.7976931348623157e308 2^^-1023
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800326 *
327 * Boundaries for double conversion to 64-bit integer:
328 * exponent 51, 52 significand bits set 4503599627370495
329 * exponent 52, 52 significand bits set 9007199254740991
330 * exponent 53, 52 bits set in significand 18014398509481982
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700331 */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700332
333/* Always four lines per test case so shell scripts can process into
Laurence Lundblade492be182025-08-09 09:45:34 -0700334 * other formats.
335 *
336 * C string literals are used because they are the shortest
337 * notation. They are used __with a length__ . Null termination
338 * doesn't work because there are bytes with value zero.
339 *
340 * While the CDE and dCBOR standards are not complete as of mid-2025,
341 * they are unlikely to change, so the tests here are likely correct.
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700342 */
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800343static const struct FloatTestCase FloatTestCases[] = {
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700344 /* Zero */
345 {0.0, 0.0f,
346 {"\xF9\x00\x00", 3}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800347 {"\xF9\x00\x00", 3}, {"\x00", 1}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700348
349 /* Negative Zero */
350 {-0.0, -0.0f,
351 {"\xF9\x80\x00", 3}, {"\xFB\x80\x00\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800352 {"\xF9\x80\x00", 3}, {"\x00", 1}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700353
354 /* NaN */
355 {NAN, NAN,
356 {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9},
357 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
358
359 /* Infinity */
360 {INFINITY, INFINITY,
361 {"\xF9\x7C\x00", 3}, {"\xFB\x7F\xF0\x00\x00\x00\x00\x00\x00", 9},
362 {"\xF9\x7C\x00", 3}, {"\xF9\x7C\x00", 3}},
363
364 /* Negative Infinity */
365 {-INFINITY, -INFINITY,
366 {"\xF9\xFC\x00", 3}, {"\xFB\xFF\xF0\x00\x00\x00\x00\x00\x00", 9},
367 {"\xF9\xFC\x00", 3}, {"\xF9\xFC\x00", 3}},
368
369 /* 1.0 */
370 {1.0, 1.0f,
371 {"\xF9\x3C\x00", 3}, {"\xFB\x3F\xF0\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800372 {"\xF9\x3C\x00", 3}, {"\x01", 1}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700373
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800374 /* -2.0 -- a negative */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700375 {-2.0, -2.0f,
376 {"\xF9\xC0\x00", 3}, {"\xFB\xC0\x00\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800377 {"\xF9\xC0\x00", 3}, {"\x21", 1}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700378
379 /* 1/3 */
380 {0.333251953125, 0.333251953125f,
381 {"\xF9\x35\x55", 3}, {"\xFB\x3F\xD5\x54\x00\x00\x00\x00\x00", 9},
382 {"\xF9\x35\x55", 3}, {"\xF9\x35\x55", 3}},
383
384 /* 5.9604644775390625E-8 -- smallest half-precision subnormal */
385 {5.9604644775390625E-8, 0.0f,
386 {"\xF9\x00\x01", 3}, {"\xFB\x3E\x70\x00\x00\x00\x00\x00\x00", 9},
387 {"\xF9\x00\x01", 3}, {"\xF9\x00\x01", 3}},
388
389 /* 3.0517578125E-5 -- a half-precision subnormal */
390 {3.0517578125E-5, 0.0f,
391 {"\xF9\x02\x00", 3}, {"\xFB\x3F\x00\x00\x00\x00\x00\x00\x00", 9},
392 {"\xF9\x02\x00", 3}, {"\xF9\x02\x00", 3}},
393
394 /* 6.097555160522461E-5 -- largest half-precision subnormal */
395 {6.097555160522461E-5, 0.0f,
396 {"\xF9\x03\xFF", 3}, {"\xFB\x3F\x0F\xF8\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800397 {"\xF9\x03\xFF", 3}, {"\xF9\x03\xFF", 3}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700398
399 /* 6.1035156249999993E-5 -- slightly smaller than smallest half-precision normal */
400 {6.1035156249999993E-5, 0.0f,
401 {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
402 {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
403
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800404 /* 6.103515625E-5 -- smallest half-precision normal */
405 {6.103515625E-5, 0.0f,
406 {"\xF9\04\00", 3}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x00", 9},
407 {"\xF9\04\00", 3}, {"\xF9\04\00", 3}},
408
409 /* 6.1035156250000014E-5 -- slightly larger than smallest half-precision normal */
410 {6.1035156250000014E-5, 0.0f,
411 {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9},
412 {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}},
413
414 /* 65504.0 -- largest half-precision */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700415 {65504.0, 0.0f,
416 {"\xF9\x7B\xFF", 3}, {"\xFB\x40\xEF\xFC\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800417 {"\xF9\x7B\xFF", 3}, {"\x19\xFF\xE0", 3}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700418
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800419 /* 65504.1 -- exponent too large and too much precision to convert to half */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700420 {65504.1, 0.0f,
421 {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9},
422 {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}},
423
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800424 /* 65536.0 -- exponent too large for half but not too much precision for single */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700425 {65536.0, 65536.0f,
426 {"\xFA\x47\x80\x00\x00", 5}, {"\xFB\x40\xF0\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800427 {"\xFA\x47\x80\x00\x00", 5}, {"\x1A\x00\x01\x00\x00", 5}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700428
429 /* 1.401298464324817e-45 -- smallest single subnormal */
430 {1.401298464324817e-45, 1.40129846E-45f,
431 {"\xFA\x00\x00\x00\x01", 5}, {"\xFB\x36\xA0\x00\x00\x00\x00\x00\x00", 9},
432 {"\xFA\x00\x00\x00\x01", 5}, {"\xFA\x00\x00\x00\x01", 5}},
433
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800434 /* 5.8774717541114375E-39 -- slightly smaller than the smallest single normal */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700435 {5.8774717541114375E-39, 5.87747175E-39f,
436 {"\xFA\x00\x40\x00\x00", 5}, {"\xFB\x38\x00\x00\x00\x00\x00\x00\x00", 9},
437 {"\xFA\x00\x40\x00\x00", 5}, {"\xFA\x00\x40\x00\x00", 5}},
438
439 /* 1.1754942106924411e-38 -- largest single subnormal */
440 {1.1754942106924411E-38, 1.17549421E-38f,
441 {"\xFA\x00\x7f\xff\xff", 5}, {"\xFB\x38\x0f\xff\xff\xC0\x00\x00\x00", 9},
442 {"\xFA\x00\x7f\xff\xff", 5}, {"\xFA\x00\x7f\xff\xff", 5} },
443
444 /* 1.1754943508222874E-38 -- slightly bigger than smallest single normal */
445 {1.1754943508222874E-38, 0.0f,
446 {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9},
447 {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}},
448
449 /* 1.1754943508222875e-38 -- smallest single normal */
450 {1.1754943508222875e-38, 1.17549435E-38f,
451 {"\xFA\x00\x80\x00\x00", 5}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x00", 9},
452 {"\xFA\x00\x80\x00\x00", 5}, {"\xFA\x00\x80\x00\x00", 5}},
453
454 /* 1.1754943508222875e-38 -- slightly bigger than smallest single normal */
455 {1.1754943508222878e-38, 0.0f,
456 {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9},
457 {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}},
458
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800459 /* 8388607 -- exponent 22 to test single exponent boundary */
460 {8388607, 8388607.0f,
461 {"\xFA\x4A\xFF\xFF\xFE", 5}, {"\xFB\x41\x5F\xFF\xFF\xC0\x00\x00\x00", 9},
462 {"\xFA\x4A\xFF\xFF\xFE", 5}, {"\x1A\x00\x7F\xFF\xFF", 5}},
463
464 /* 16777215 -- exponent 23 to test single exponent boundary */
465 {16777215, 16777215.0f,
466 {"\xFA\x4B\x7F\xFF\xFF", 5}, {"\xFB\x41\x6F\xFF\xFF\xE0\x00\x00\x00", 9},
467 {"\xFA\x4B\x7F\xFF\xFF", 5}, {"\x1A\x00\xFF\xFF\xFF", 5}},
468
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700469 /* 16777216 -- converts to single without loss */
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800470 {16777216, 16777216.0f,
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700471 {"\xFA\x4B\x80\x00\x00", 5}, {"\xFB\x41\x70\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800472 {"\xFA\x4B\x80\x00\x00", 5}, {"\x1A\x01\x00\x00\x00", 5}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700473
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800474 /* 16777217 -- one more than above and fails conversion to single because of precision */
475 {16777217, 0.0f,
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700476 {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800477 {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\x1A\x01\x00\x00\x01", 5}},
Laurence Lundblade492be182025-08-09 09:45:34 -0700478
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800479 /* 33554430 -- exponent 24 to test single exponent boundary */
480 {33554430, 33554430.0f,
481 {"\xFA\x4B\xFF\xFF\xFF", 5}, {"\xFB\x41\x7F\xFF\xFF\xE0\x00\x00\x00", 9},
482 {"\xFA\x4B\xFF\xFF\xFF", 5}, {"\x1A\x01\xFF\xFF\xFE", 5}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700483
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800484 /* 4294967295 -- 2^^32 - 1 UINT32_MAX */
485 {4294967295, 0,
486 {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9},
487 {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\x1A\xFF\xFF\xFF\xFF", 5}},
488
489 /* 4294967296 -- 2^^32, UINT32_MAX + 1 */
490 {4294967296, 4294967296.0f,
491 {"\xFA\x4F\x80\x00\x00", 5}, {"\xFB\x41\xF0\x00\x00\x00\x00\x00\x00", 9},
492 {"\xFA\x4F\x80\x00\x00", 5}, {"\x1B\x00\x00\x00\x01\x00\x00\x00\x00", 9}},
493
494 /* 2251799813685248 -- exponent 51, 0 significand bits set, to test double exponent boundary */
495 {2251799813685248, 2251799813685248.0f,
496 {"\xFA\x59\x00\x00\x00", 5}, {"\xFB\x43\x20\x00\x00\x00\x00\x00\x00", 9},
497 {"\xFA\x59\x00\x00\x00", 5}, {"\x1B\x00\x08\x00\x00\x00\x00\x00\x00", 9}},
498
499 /* 4503599627370495 -- exponent 51, 52 significand bits set to test double exponent boundary*/
500 {4503599627370495, 0,
501 {"\xFB\x43\x2F\xFF\xFF\xFF\xFF\xFF\xFE", 9}, {"\xFB\x43\x2F\xFF\xFF\xFF\xFF\xFF\xFE", 9},
502 {"\xFB\x43\x2F\xFF\xFF\xFF\xFF\xFF\xFE", 9}, {"\x1B\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
503
504 /* 9007199254740991 -- exponent 52, 52 significand bits set to test double exponent boundary */
505 {9007199254740991, 0,
506 {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
507 {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\x00\x1F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
508
Laurence Lundblade492be182025-08-09 09:45:34 -0700509 /* 18014398509481982 -- exponent 53, 52 bits set in significand (double lacks precision for 18014398509481983) */
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800510 {18014398509481982, 0,
511 {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
512 {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFE", 9}},
513
514 /* 18014398509481984 -- next largest possible double above 18014398509481982 */
515 {18014398509481984, 18014398509481984.0f,
516 {"\xFA\x5A\x80\x00\x00", 5}, {"\xFB\x43\x50\x00\x00\x00\x00\x00\x00", 9},
517 {"\xFA\x5A\x80\x00\x00", 5}, {"\x1B\x00\x40\x00\x00\x00\x00\x00\x00", 9}},
Laurence Lundblade492be182025-08-09 09:45:34 -0700518
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800519 /* 18446742974197924000.0.0 -- largest single that can convert to uint64 */
520 {18446742974197924000.0, 18446742974197924000.0f,
521 {"\xFA\x5F\x7F\xFF\xFF", 5}, {"\xFB\x43\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
522 {"\xFA\x5F\x7F\xFF\xFF", 5}, {"\x1B\xFF\xFF\xFF\x00\x00\x00\x00\x00", 9}},
523
524 /* 18446744073709550000.0 -- largest double that can convert to uint64, almost UINT64_MAX (18446744073709551615) */
525 {18446744073709550000.0, 0,
526 {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
527 {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00", 9}},
528
529 /* 18446744073709552000.0 -- just too large to convert to uint64, but converts to a single, just over UINT64_MAX */
530 {18446744073709552000.0, 18446744073709552000.0f,
531 {"\xFA\x5F\x80\x00\x00", 5}, {"\xFB\x43\xF0\x00\x00\x00\x00\x00\x00", 9},
532 {"\xFA\x5F\x80\x00\x00", 5}, {"\xFA\x5F\x80\x00\x00", 5}},
533
534 /* -4294967295 -- negative UINT32_MAX */
535 {-4294967295.0, 0,
536 {"\xFB\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\xFB\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", 9},
537 {"\xFB\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\x3A\xFF\xFF\xFF\xFE", 5}},
538
539 /* -9223372036854774784.0 -- most negative double that converts to int64 */
540 {-9223372036854774784.0, 0,
541 {"\xFB\xC3\xDF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\xC3\xDF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
542 {"\xFB\xC3\xDF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x3B\x7F\xFF\xFF\xFF\xFF\xFF\xFB\xFF", 9}},
543
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700544 /* -18446742974197923840.0 -- large negative that converts to float, but too large for int64 */
545 {-18446742974197923840.0, -18446742974197923840.0f,
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800546 {"\xFA\xDF\x7F\xFF\xFF", 5}, {"\xFB\xC3\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700547 {"\xFA\xDF\x7F\xFF\xFF", 5}, {"\x3B\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF", 9}},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800548
549 /* 3.4028234663852886E+38 -- largest possible single */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700550 {3.4028234663852886E+38, 3.40282347E+38f,
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800551 {"\xFA\x7F\x7F\xFF\xFF", 5}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
552 {"\xFA\x7F\x7F\xFF\xFF", 5}, {"\xFA\x7F\x7F\xFF\xFF", 5}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700553
554 /* 3.402823466385289E+38 -- slightly larger than largest possible single */
555 {3.402823466385289E+38, 0.0f,
556 {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9},
557 {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}},
558
559 /* 3.402823669209385e+38 -- exponent larger by one than largest possible single */
560 {3.402823669209385e+38, 0.0f,
561 {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9},
562 {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}},
563
564 /* 5.0e-324 -- smallest double subnormal normal */
565 {5.0e-324, 0.0f,
566 {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9},
567 {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}},
568
569 /* 2.2250738585072009E−308 -- largest double subnormal */
570 {2.2250738585072009e-308, 0.0f,
571 {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
572 {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
573
574 /* 2.2250738585072014e-308 -- smallest double normal */
575 {2.2250738585072014e-308, 0.0f,
576 {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9},
577 {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}},
578
579 /* 1.7976931348623157E308 -- largest double normal */
580 {1.7976931348623157e308, 0.0f,
581 {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
582 {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
583
Laurence Lundblade534112f2025-02-26 15:12:47 -0700584 /* -18446744073709551616.0 -- largest that encodes into negative uint64 (65-bit neg) */
585 {-18446744073709551616.0, -18446744073709551616.0f,
586 {"\xFA\xDF\x80\x00\x00", 5}, {"\xFB\xC3\xF0\x00\x00\x00\x00\x00\x00", 9},
587 {"\xFA\xDF\x80\x00\x00", 5}, {"\x3B\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
588
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700589 /* List terminator */
590 {0.0, 0.0f, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700591};
592
593
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700594/* Public function. See float_tests.h
595 *
596 * This is the main test of floating-point encoding / decoding. It is
597 * data-driven by the above tables. It works better than tests below that
598 * it mostly replaces because it tests one number at a time, rather than
599 * putting them all in a map. It is much easier to debug test failures
600 * and to add new tests. */
601int32_t
602FloatValuesTests(void)
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700603{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700604 unsigned int uTestIndex;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800605 const struct FloatTestCase *pTestCase;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700606 MakeUsefulBufOnStack( TestOutBuffer, 20);
607 UsefulBufC TestOutput;
608 QCBOREncodeContext EnCtx;
609 QCBORError uErr;
610 QCBORDecodeContext DCtx;
611 QCBORItem Item;
612 uint64_t uDecoded;
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700613
Laurence Lundblade492be182025-08-09 09:45:34 -0700614 /* Test a variety of doubles and some singles */
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800615 for(uTestIndex = 0; FloatTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
616 pTestCase = &FloatTestCases[uTestIndex];
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700617
Laurence Lundblade492be182025-08-09 09:45:34 -0700618 if(uTestIndex == 16) {
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800619 uDecoded = 1;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700620 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800621
Laurence Lundblade492be182025-08-09 09:45:34 -0700622 /* Preferred Encode */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700623 QCBOREncode_Init(&EnCtx, TestOutBuffer);
624 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
625 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800626
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700627 if(uErr != QCBOR_SUCCESS) {
628 return MakeTestResultCode(uTestIndex, 1, uErr);;
629 }
Laurence Lundblade492be182025-08-09 09:45:34 -0700630#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700631 if(UsefulBuf_Compare(TestOutput, pTestCase->Preferred)) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700632 return MakeTestResultCode(uTestIndex, 2, 200);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700633 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700634
Laurence Lundblade492be182025-08-09 09:45:34 -0700635 if(CompareToCarsten(UsefulBufUtil_CopyDoubleToUint64(pTestCase->dNumber), TestOutput, pTestCase->Preferred)) {
636 return MakeTestResultCode(uTestIndex, 202, 200);
637 }
638#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
639 if(UsefulBuf_Compare(TestOutput, pTestCase->NotPreferred)) {
640 return MakeTestResultCode(uTestIndex, 3, 200);
641 }
642#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
643
644 /* Non-Preferred Encode */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700645 QCBOREncode_Init(&EnCtx, TestOutBuffer);
646 QCBOREncode_AddDoubleNoPreferred(&EnCtx, pTestCase->dNumber);
647 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
Laurence Lundblade68a13352018-09-23 02:19:54 -0700648
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700649 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700650 return MakeTestResultCode(uTestIndex, 4, uErr);;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700651 }
652 if(UsefulBuf_Compare(TestOutput, pTestCase->NotPreferred)) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700653 return MakeTestResultCode(uTestIndex, 5, 200);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700654 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800655
Laurence Lundblade492be182025-08-09 09:45:34 -0700656#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
657 /* Deterministic Encode */
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800658 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade82634b62024-11-20 22:37:45 -0800659 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_CDE);
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800660 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
661 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
662
663 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700664 return MakeTestResultCode(uTestIndex, 6, uErr);;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800665 }
666 if(UsefulBuf_Compare(TestOutput, pTestCase->CDE)) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700667 return MakeTestResultCode(uTestIndex, 7, 200);
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800668 }
669
Laurence Lundblade492be182025-08-09 09:45:34 -0700670 /* dCBOR Encode */
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800671 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade82634b62024-11-20 22:37:45 -0800672 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR);
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800673 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
674 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
675
676 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700677 return MakeTestResultCode(uTestIndex, 8, uErr);;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800678 }
679 if(UsefulBuf_Compare(TestOutput, pTestCase->DCBOR)) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700680 return MakeTestResultCode(uTestIndex, 9, 200);
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800681 }
Laurence Lundblade492be182025-08-09 09:45:34 -0700682#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800683
Laurence Lundblade492be182025-08-09 09:45:34 -0700684 /* Decode Preferred */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700685 QCBORDecode_Init(&DCtx, pTestCase->Preferred, 0);
686 uErr = QCBORDecode_GetNext(&DCtx, &Item);
Laurence Lundblade492be182025-08-09 09:45:34 -0700687#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700688 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700689 return MakeTestResultCode(uTestIndex, 10, uErr);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700690 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700691 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700692 return MakeTestResultCode(uTestIndex, 11, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700693 }
694 if(isnan(pTestCase->dNumber)) {
695 if(!isnan(Item.val.dfnum)) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700696 return MakeTestResultCode(uTestIndex, 12, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700697 }
698 } else {
699 if(Item.val.dfnum != pTestCase->dNumber) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700700 return MakeTestResultCode(uTestIndex, 13, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700701 }
702 }
Laurence Lundblade492be182025-08-09 09:45:34 -0700703#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
704 if(pTestCase->Preferred.len == 3) {
705 if(uErr != QCBOR_ERR_PREFERRED_FLOAT_DISABLED) {
706 return MakeTestResultCode(uTestIndex, 14, uErr);
707 }
708 } else if(pTestCase->Preferred.len == 5) {
709 /* When QCBOR_DISABLE_PREFERRED_FLOAT is set, single-precision is not
710 * converted to double when decoding, so test differently. len == 5
711 * indicates single-precision in the encoded CBOR. */
712 if(uErr != QCBOR_SUCCESS) {
713 return MakeTestResultCode(uTestIndex, 15, uErr);
714 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700715 if(Item.uDataType != QCBOR_TYPE_FLOAT) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700716 return MakeTestResultCode(uTestIndex, 16, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700717 }
718 if(isnan(pTestCase->dNumber)) {
719 if(!isnan(Item.val.fnum)) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700720 return MakeTestResultCode(uTestIndex, 17, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700721 }
722 } else {
723 if(Item.val.fnum != pTestCase->fNumber) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700724 return MakeTestResultCode(uTestIndex, 18, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700725 }
726 }
727 } else {
Laurence Lundblade492be182025-08-09 09:45:34 -0700728 if(uErr != QCBOR_SUCCESS) {
729 return MakeTestResultCode(uTestIndex, 19, uErr);
730 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700731 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700732 return MakeTestResultCode(uTestIndex, 20, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700733 }
734 if(isnan(pTestCase->dNumber)) {
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700735 if(!isnan(Item.val.dfnum)) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700736 return MakeTestResultCode(uTestIndex, 21, 0);
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700737 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700738 } else {
739 if(Item.val.dfnum != pTestCase->dNumber) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700740 return MakeTestResultCode(uTestIndex, 22, 0);
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700741 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700742 }
743 }
Laurence Lundblade492be182025-08-09 09:45:34 -0700744#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700745
Laurence Lundblade492be182025-08-09 09:45:34 -0700746 /* Decode Not Preferred */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700747 QCBORDecode_Init(&DCtx, pTestCase->NotPreferred, 0);
748 uErr = QCBORDecode_GetNext(&DCtx, &Item);
749 if(uErr != QCBOR_SUCCESS) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700750 return MakeTestResultCode(uTestIndex, 23, uErr);;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700751 }
752 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700753 return MakeTestResultCode(uTestIndex, 24, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700754 }
755 if(isnan(pTestCase->dNumber)) {
756 if(!isnan(Item.val.dfnum)) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700757 return MakeTestResultCode(uTestIndex, 25, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700758 }
759 } else {
760 if(Item.val.dfnum != pTestCase->dNumber) {
Laurence Lundblade492be182025-08-09 09:45:34 -0700761 return MakeTestResultCode(uTestIndex, 26, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700762 }
763 }
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700764 }
765
766 return 0;
Laurence Lundblade570fab52018-10-13 18:28:27 +0800767}
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700768
769
Laurence Lundblade492be182025-08-09 09:45:34 -0700770/* Can't use the types double and float here because there's no compile
771 * time initializer in C to construct NaNs.
772
773 * The tests: encode the double in the 4 different ways and see the result is as expected
774 * encode the single in the 4 different ways and see the result is as expected
775 * decode the preferred and non-preferred (CDE is always the same as preferred; DCBOR is not reversable)
776 */
777struct NaNTestCase {
778 uint64_t uDouble; /* Converted to double in test */
779 uint32_t uSingle; /* Converted to single in test */
780 uint64_t uExpectedDouble;
781 uint32_t uExpectedSingle;
782 UsefulBufC Preferred;
783 UsefulBufC NotPreferred;
784 UsefulBufC CDE;
785 UsefulBufC DCBOR;
786};
787
788/* Always four lines per test case so shell scripts can process into
789 * other formats.
790 *
791 * C string literals are used because they are the shortest
792 * notation. They are used __with a length__ . Null termination
793 * doesn't work because there are bytes with value zero.
794 *
795 * While the CDE and dCBOR standards are not complete as of mid-2025,
796 * they are unlikely to change, so the tests here are likely correct.
797 */
798/* This assumes that the signficand of a float is made up of the qNaN bit and
799 * the payload. The qNaN bit is the most signficant. If not a qNaN, then it
800 * is an sNaN. For an sNaN not to be the floating point value, its significand
801 * must be non-zero. */
802static const struct NaNTestCase NaNTestCases[] = {
803 /* Reminder: DOUBLE_NAN_BITS | x00 is INFINITY, not a NaN */
804
805 /* double qNaN -- shortens to half */
806 {DOUBLE_NAN_BITS | DOUBLE_QNAN, 0,
807 DOUBLE_NAN_BITS | DOUBLE_QNAN, 0,
808 {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9},
809 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
810
811 /* double negative qNaN -- shortens to half */
812 {DOUBLE_SIGN_MASK | DOUBLE_NAN_BITS | DOUBLE_QNAN, 0,
813 DOUBLE_SIGN_MASK| DOUBLE_NAN_BITS | DOUBLE_QNAN, 0,
814 {"\xF9\xFE\x00", 3}, {"\xFB\xFF\xF8\x00\x00\x00\x00\x00\x00", 9},
815 {"\xF9\xFE\x00", 3}, {"\xF9\x7E\x00", 3}},
816
817 /* double sNaN with payload of rightmost bit set -- no shorter encoding */
818 {DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x01, 0,
819 DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x01, 0,
820 {"\xFB\x7F\xF0\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x7F\xF0\x00\x00\x00\x00\x00\x01", 9},
821 {"\xFB\x7F\xF0\x00\x00\x00\x00\x00\x01", 9}, {"\xF9\x7E\x00", 3}},
822
823 /* double negative sNaN with payload of rightmost bit set -- no shorter encoding */
824 {DOUBLE_SIGN_MASK | DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x01, 0,
825 DOUBLE_SIGN_MASK | DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x01, 0,
826 {"\xFB\xFF\xF0\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\xFF\xF0\x00\x00\x00\x00\x00\x01", 9},
827 {"\xFB\xFF\xF0\x00\x00\x00\x00\x00\x01", 9}, {"\xF9\x7E\x00", 3}},
828
829 /* double qNaN with 9 leftmost payload bits set -- shortens to half */
830 {DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7fc0000000000, 0,
831 DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7fc0000000000, 0,
832 {"\xF9\x7F\xFF", 3}, {"\xFB\x7F\xFF\xFC\x00\x00\x00\x00\x00", 9},
833 {"\xF9\x7F\xFF", 3}, {"\xF9\x7E\x00", 3}},
834
835 /* double sNaN with 10 rightmost payload bits set -- no shorter encoding */
836 {DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x03ff, 0,
837 DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x03ff, 0,
838 {"\xFB\x7F\xF0\x00\x00\x00\x00\x03\xFF", 9}, {"\xFB\x7F\xF0\x00\x00\x00\x00\x03\xFF", 9},
839 {"\xFB\x7F\xF0\x00\x00\x00\x00\x03\xFF", 9}, {"\xF9\x7E\x00", 3}},
840
841 /* double qNaN with 22 leftmost payload bits set -- shortens to single */
842 {DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7ffffe0000000, 0,
843 DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7ffffe0000000, SINGLE_NAN_BITS | 0x7fffff,
844 {"\xFA\x7F\xFF\xFF\xFF", 5}, {"\xFB\x7F\xFF\xFF\xFF\xE0\x00\x00\x00", 9},
845 {"\xFA\x7F\xFF\xFF\xFF", 5}, {"\xF9\x7E\x00", 3}},
846
847 /* double negative qNaN with 22 leftmost payload bits set -- shortens to single */
848 {DOUBLE_SIGN_MASK | DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7ffffe0000000, 0,
849 DOUBLE_SIGN_MASK | DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7ffffe0000000, SINGLE_SIGN_MASK | SINGLE_NAN_BITS | 0x7fffff,
850 {"\xFA\xFF\xFF\xFF\xFF", 5}, {"\xFB\xFF\xFF\xFF\xFF\xE0\x00\x00\x00", 9},
851 {"\xFA\xFF\xFF\xFF\xFF", 5}, {"\xF9\x7E\x00", 3}},
852
853 /* double sNaN with 23rd leftmost payload bit set -- shortens to single */
854 {DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x0000020000000, 0,
855 DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x0000020000000, SINGLE_NAN_BITS | 0x01,
856 {"\xFA\x7F\x80\x00\x01", 5}, {"\xFB\x7F\xF0\x00\x00\x20\x00\x00\x00", 9},
857 {"\xFA\x7F\x80\x00\x01", 5}, {"\xF9\x7E\x00", 3}},
858
859 /* double sNaN with randomly chosen bit pattern -- shortens to single */
860 {DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x43d7c40000000, 0,
861 DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x43d7c40000000, SINGLE_NAN_BITS | 0x21ebe2,
862 {"\xFA\x7F\xA1\xEB\xE2", 5}, {"\xFB\x7F\xF4\x3D\x7C\x40\x00\x00\x00", 9},
863 {"\xFA\x7F\xA1\xEB\xE2", 5}, {"\xF9\x7E\x00", 3}},
864
865 /* double sNaN with 23 leftmost payload bits set -- no shorter encoding */
866 {DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x7fffff0000000, 0,
867 DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x7fffff0000000, 0,
868 {"\xFB\x7F\xF7\xFF\xFF\xF0\x00\x00\x00", 9}, {"\xFB\x7F\xF7\xFF\xFF\xF0\x00\x00\x00", 9},
869 {"\xFB\x7F\xF7\xFF\xFF\xF0\x00\x00\x00", 9}, {"\xF9\x7E\x00", 3}},
870
871 /* double qNaN with all bits set -- no shorter encoding */
872 {DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7ffffffffffff, 0,
873 DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7ffffffffffff, 0,
874 {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
875 {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xF9\x7E\x00", 3}},
876
877 /* single qNaN with payload 0x00 -- shortens to half */
878 {0, SINGLE_NAN_BITS | SINGLE_QNAN,
879 DOUBLE_NAN_BITS | DOUBLE_QNAN, 0,
880 {"\xF9\x7E\x00", 3}, {"\xFA\x7F\xC0\x00\x00", 5},
881 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
882
883 /* sNan with payload 0x00 is not a NaN, it's infinity */
884
885 /* single sNan with payload 0x01 -- no shorter encoding */
886 {0, SINGLE_NAN_BITS | SINGLE_SNAN | 0x01,
887 DOUBLE_NAN_BITS | (0x01 << 29), 0,
888 {"\xFA\x7F\x80\x00\x01", 5}, {"\xFA\x7F\x80\x00\x01", 5},
889 {"\xFA\x7F\x80\x00\x01", 5}, {"\xF9\x7E\x00", 3}},
890
891 /* single qNaN with 9 bit payload -- shortens to half */
892 {0, SINGLE_NAN_BITS | SINGLE_QNAN | 0x3fe000,
893 DOUBLE_NAN_BITS | ((SINGLE_QNAN | 0x3fe000ULL) << 29), 0,
894 {"\xF9\x7F\xFF", 3}, {"\xFA\x7F\xFF\xE0\x00", 5},
895 {"\xF9\x7F\xFF", 3}, {"\xF9\x7E\x00", 3}},
896
897 /* single qNaN with 10 bit payload -- no shorter encoding */
898 {0, SINGLE_NAN_BITS | SINGLE_QNAN | 0x3ff000,
899 DOUBLE_NAN_BITS | ((SINGLE_QNAN | 0x3ff000ULL) << 29), 0,
900 {"\xFA\x7F\xFF\xF0\x00", 5}, {"\xFA\x7F\xFF\xF0\x00", 5},
901 {"\xFA\x7F\xFF\xF0\x00", 5}, {"\xF9\x7E\x00", 3}},
902
903 /* single sNaN with 9 bit payload -- shortens to half */
904 {0, SINGLE_NAN_BITS | SINGLE_SNAN | 0x3fe000,
905 DOUBLE_NAN_BITS | ((SINGLE_SNAN | 0x3fe000ULL) << 29), 0,
906 {"\xF9\x7D\xFF", 3}, {"\xFA\x7F\xBF\xE0\x00", 5},
907 {"\xF9\x7D\xFF", 3}, {"\xF9\x7E\x00", 3}},
908
909 /* single sNaN with 10 bit payload -- no shorter encoding */
910 {0, SINGLE_NAN_BITS | SINGLE_SNAN | 0x3ff000,
911 DOUBLE_NAN_BITS | ((SINGLE_SNAN | 0x3ff000ULL) << 29), 0,
912 {"\xFA\x7F\xBF\xF0\x00", 5}, {"\xFA\x7F\xBF\xF0\x00", 5},
913 {"\xFA\x7F\xBF\xF0\x00", 5}, {"\xF9\x7E\x00", 3}},
914
915 /* List terminator */
916 {0, 0, 0, 0, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} }
917};
918
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700919
920/* Public function. See float_tests.h */
Laurence Lundblade492be182025-08-09 09:45:34 -0700921int32_t
922NaNPayloadsTest(void)
923{
924 const struct NaNTestCase *pNaNTestCase;
925 unsigned int uTestIndex;
926 QCBORError uErr;
927 QCBOREncodeContext EnCtx;
928 MakeUsefulBufOnStack( TestOutBuffer, 20);
929 UsefulBufC TestOutput;
930 QCBORDecodeContext DCtx;
931 QCBORItem Item;
932 uint64_t uDecoded;
933
934 /* Test a variety of NaNs with payloads */
935 for(uTestIndex = 0; NaNTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
936 pNaNTestCase = &NaNTestCases[uTestIndex];
937
938 if(uTestIndex == 7) {
939 uErr = 99; /* For setting break points for a particular test */
940 }
941
942 if(pNaNTestCase->uDouble) {
943 /* NaN Encode of Preferred */
944 QCBOREncode_Init(&EnCtx, TestOutBuffer);
945 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
946 QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
947 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
948 if(uErr != QCBOR_SUCCESS) {
949 return MakeTestResultCode(uTestIndex+100, 10, uErr);;
950 }
951#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
952 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) {
953 return MakeTestResultCode(uTestIndex+100, 11, 200);
954 }
955 if(CompareToCarsten(pNaNTestCase->uDouble, TestOutput, pNaNTestCase->Preferred)) {
956 return MakeTestResultCode(uTestIndex+100, 12, 200);
957 }
958#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
959 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
960 return MakeTestResultCode(uTestIndex+100, 122, 200);
961 }
962#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
963
964 if(HWCheckFloatToDouble(pNaNTestCase->uDouble, pNaNTestCase->uSingle)) {
965 return MakeTestResultCode(uTestIndex+100, 121, 200);
966 }
967
968 /* NaN Encode of Not Preferred */
969 QCBOREncode_Init(&EnCtx, TestOutBuffer);
970 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
971 QCBOREncode_AddDoubleNoPreferred(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
972 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
973 if(uErr != QCBOR_SUCCESS) {
974 return MakeTestResultCode(uTestIndex+100, 13, uErr);;
975 }
976 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
977 return MakeTestResultCode(uTestIndex+100, 14, 200);
978 }
979
980 /* NaN Decode of Preferred */
981 QCBORDecode_Init(&DCtx, pNaNTestCase->Preferred, 0);
982 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
983 uErr = QCBORDecode_GetNext(&DCtx, &Item);
984#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
985 if(uErr != QCBOR_SUCCESS) {
986 return MakeTestResultCode(uTestIndex+100, 15, uErr);
987 }
988 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
989 if(uDecoded != pNaNTestCase->uDouble) {
990 return MakeTestResultCode(uTestIndex+100, 11, 200);
991 }
992#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
993 if(pNaNTestCase->Preferred.len == 9) {
994 if(uErr != QCBOR_SUCCESS) {
995 return MakeTestResultCode(uTestIndex+100, 17, uErr);
996 }
997
998 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
999 if(uDecoded != pNaNTestCase->uDouble) {
1000 return MakeTestResultCode(uTestIndex+100, 18, 200);
1001 }
1002 } else if(pNaNTestCase->Preferred.len == 5) {
1003 if(Item.uDataType != QCBOR_TYPE_FLOAT) {
1004 return MakeTestResultCode(uTestIndex, 19, 0);
1005 }
1006
1007 uint32_t uDecoded2x = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum);
1008
1009 if(uDecoded2x != pNaNTestCase->uExpectedSingle) {
1010 return MakeTestResultCode(uTestIndex, 20, 0);
1011 }
1012 } else {
1013 /* Serialized to half precision */
1014 if(Item.uDataType != QCBOR_TYPE_NONE) {
1015 return MakeTestResultCode(uTestIndex, 21, 0);
1016 }
1017 }
1018#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1019
1020 /* NaN Decode of Not Preferred */
1021 QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0);
1022 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
1023 uErr = QCBORDecode_GetNext(&DCtx, &Item);
1024 if(uErr != QCBOR_SUCCESS) {
1025 return MakeTestResultCode(uTestIndex+100, 22, uErr);
1026 }
1027 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
1028 if(uDecoded != pNaNTestCase->uDouble) {
1029 return MakeTestResultCode(uTestIndex+100, 23, 200);
1030 }
1031
1032 /* NaN Encode of CDE */
1033 QCBOREncode_Init(&EnCtx, TestOutBuffer);
1034 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_CDE| QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
1035 QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
1036 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
1037 if(uErr != QCBOR_SUCCESS) {
1038 return MakeTestResultCode(uTestIndex+100, 24, uErr);;
1039 }
1040#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1041 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) {
1042 return MakeTestResultCode(uTestIndex+100, 241, 200);
1043 }
1044#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1045 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
1046 return MakeTestResultCode(uTestIndex+100, 25, 200);
1047 }
1048#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1049
1050 /* NaN Encode of DCBOR */
1051 QCBOREncode_Init(&EnCtx, TestOutBuffer);
1052 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR | QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
1053 QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
1054 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
1055#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1056 if(uErr != QCBOR_SUCCESS) {
1057 return MakeTestResultCode(uTestIndex+100, 26, uErr);;
1058 }
1059 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->DCBOR)) {
1060 return MakeTestResultCode(uTestIndex+100, 27, 200);
1061 }
1062#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1063 if(uErr != QCBOR_ERR_PREFERRED_FLOAT_DISABLED) {
1064 return MakeTestResultCode(uTestIndex+100, 28, uErr);
1065 }
1066#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1067
1068 } else {
1069 /* --- uSingle tests ---- */
1070 /* NaN Encode of Preferred */
1071 QCBOREncode_Init(&EnCtx, TestOutBuffer);
1072 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
1073 QCBOREncode_AddFloat(&EnCtx, UsefulBufUtil_CopyUint32ToFloat(pNaNTestCase->uSingle));
1074 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
1075 if(uErr != QCBOR_SUCCESS) {
1076 return MakeTestResultCode(uTestIndex+100, 29, uErr);;
1077 }
1078#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1079 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) {
1080 return MakeTestResultCode(uTestIndex+100, 30, 200);
1081 }
1082#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1083 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
1084 return MakeTestResultCode(uTestIndex+100, 31, 200);
1085 }
1086#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1087
1088 /* NaN Encode of Not Preferred */
1089 QCBOREncode_Init(&EnCtx, TestOutBuffer);
1090 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
1091 QCBOREncode_AddFloatNoPreferred(&EnCtx, UsefulBufUtil_CopyUint32ToFloat(pNaNTestCase->uSingle));
1092 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
1093 if(uErr != QCBOR_SUCCESS) {
1094 return MakeTestResultCode(uTestIndex+100, 32, uErr);;
1095 }
1096 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
1097 return MakeTestResultCode(uTestIndex+100, 33, 200);
1098 }
1099
1100 /* NaN Decode of Preferred */
1101 QCBORDecode_Init(&DCtx, pNaNTestCase->Preferred, 0);
1102 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
1103 uErr = QCBORDecode_GetNext(&DCtx, &Item);
1104#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1105 if(uErr != QCBOR_SUCCESS) {
1106 return MakeTestResultCode(uTestIndex+100, 34, uErr);
1107 }
1108 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
1109 if(uDecoded != pNaNTestCase->uExpectedDouble) {
1110 return MakeTestResultCode(uTestIndex+100, 35, 200);
1111 }
1112#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1113 if(pNaNTestCase->Preferred.len == 5) {
1114 uint32_t uDecoded2x = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum);
1115 if(uDecoded2x != pNaNTestCase->uSingle) {
1116 return MakeTestResultCode(uTestIndex+100, 36, 200);
1117 }
1118 } else {
1119 if(uErr != QCBOR_ERR_PREFERRED_FLOAT_DISABLED) {
1120 return MakeTestResultCode(uTestIndex+100, 37, 200);
1121 }
1122 }
1123#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1124
1125 /* NaN Decode of Not Preferred */
1126 QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0);
1127 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
1128 uErr = QCBORDecode_GetNext(&DCtx, &Item);
1129 if(uErr != QCBOR_SUCCESS) {
1130 return MakeTestResultCode(uTestIndex+100, 38, uErr);
1131 }
1132#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1133 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
1134 if(uDecoded != pNaNTestCase->uExpectedDouble) {
1135 return MakeTestResultCode(uTestIndex+100, 39, 200);
1136 }
1137#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1138 if(pNaNTestCase->NotPreferred.len == 5) {
1139 uint32_t uDecoded22 = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum);
1140 if(uDecoded22 != pNaNTestCase->uSingle) {
1141 return MakeTestResultCode(uTestIndex+100, 40, 200);
1142 }
1143 }
1144#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1145
1146 if(HWCheckDoubleToFloat(pNaNTestCase->uSingle, pNaNTestCase->uExpectedDouble)) {
1147 return MakeTestResultCode(uTestIndex+100, 401, 200);
1148 }
1149
1150 /* NaN Encode of CDE */
1151 QCBOREncode_Init(&EnCtx, TestOutBuffer);
1152 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_CDE| QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
1153 QCBOREncode_AddFloat(&EnCtx, UsefulBufUtil_CopyUint32ToFloat(pNaNTestCase->uSingle));
1154 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
1155 if(uErr != QCBOR_SUCCESS) {
1156 return MakeTestResultCode(uTestIndex+100, 41, uErr);;
1157 }
1158#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1159 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->CDE)) {
1160 return MakeTestResultCode(uTestIndex+100, 42, 200);
1161 }
1162#else /* ! #ifndef QCBOR_DISABLE_PREFERRED_FLOAT */
1163 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
1164 return MakeTestResultCode(uTestIndex+100, 43, 200);
1165 }
1166#endif /* ! #ifndef QCBOR_DISABLE_PREFERRED_FLOAT */
1167
1168 /* NaN Encode of DCBOR */
1169 QCBOREncode_Init(&EnCtx, TestOutBuffer);
1170 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR | QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
1171 QCBOREncode_AddFloat(&EnCtx, UsefulBufUtil_CopyUint32ToFloat(pNaNTestCase->uSingle));
1172 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
1173#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1174 if(uErr != QCBOR_SUCCESS) {
1175 return MakeTestResultCode(uTestIndex+100, 44, uErr);;
1176 }
1177 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->DCBOR)) {
1178 return MakeTestResultCode(uTestIndex+100, 45, 200);
1179 }
1180#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1181 if(uErr != QCBOR_ERR_PREFERRED_FLOAT_DISABLED) {
1182 return MakeTestResultCode(uTestIndex+100, 46, uErr);
1183 }
1184#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1185 }
1186 }
1187
1188 /* Special one-off for 100% coverage */
1189 QCBOREncode_Init(&EnCtx, TestOutBuffer);
1190 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR);
1191 QCBOREncode_AddFloat(&EnCtx, 0);
1192 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
1193#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1194 if(uErr != QCBOR_SUCCESS) {
1195 return MakeTestResultCode(199, 100, uErr);;
1196 }
1197 if(UsefulBuf_Compare(TestOutput, UsefulBuf_FROM_SZ_LITERAL("\x00"))) {
1198 return MakeTestResultCode(199, 101, 200);
1199 }
1200#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1201 if(uErr != QCBOR_ERR_PREFERRED_FLOAT_DISABLED) {
1202 return MakeTestResultCode(uTestIndex+100, 261, uErr);
1203 }
1204#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
1205
1206 return 0;
1207}
1208
1209
1210/* Public function. See float_tests.h */
1211int32_t
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001212HalfPrecisionAgainstRFCCodeTest(void)
1213{
1214 QCBORItem Item;
1215 QCBORDecodeContext DC;
1216 unsigned char pbHalfBytes[2];
1217 uint8_t uHalfPrecInitialByte;
1218 double d;
1219 UsefulBuf_MAKE_STACK_UB(EncodedBytes, 3);
1220 UsefulOutBuf UOB;
1221 uint32_t uHalfP;
1222
1223
1224 for(uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
1225 pbHalfBytes[1] = (uint8_t)(uHalfP & 0xff);
1226 pbHalfBytes[0] = (uint8_t)(uHalfP >> 8); /* uHalfP is always less than 0xffff */
1227 d = decode_half(pbHalfBytes);
1228
1229 /* Construct the CBOR for the half-precision float by hand */
1230 UsefulOutBuf_Init(&UOB, EncodedBytes);
1231
1232 uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); /* 0xf9 */
1233 UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); /* initial byte */
1234 UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP); /* argument */
1235
1236 /* Now parse the hand-constructed CBOR. This will invoke the
1237 * conversion to a float
1238 */
1239 QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
1240 QCBORDecode_GetNext(&DC, &Item);
1241 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
1242 return -1;
1243 }
1244
1245 if(isnan(d)) {
1246 /* The RFC code uses the native instructions which may or may not
1247 * handle sNaN, qNaN and NaN payloads correctly. This test just
1248 * makes sure it is a NaN and doesn't worry about the type of NaN
1249 */
1250 if(!isnan(Item.val.dfnum)) {
1251 return -3;
1252 }
1253 } else {
1254 if(Item.val.dfnum != d) {
1255 return -2;
1256 }
1257 }
1258 }
1259 return 0;
1260}
1261
Laurence Lundblade492be182025-08-09 09:45:34 -07001262#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundbladed711fb22018-09-26 14:35:22 -07001263
1264
Laurence Lundblade32f3e622020-07-13 20:35:11 -07001265/*
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001266 * Some encoded floating point numbers that are used for both
1267 * encode and decode tests.
1268 *
1269 * [0.0, // Half
1270 * 3.14, // Double
1271 * 0.0, // Double
1272 * NaN, // Double
1273 * Infinity, // Double
1274 * 0.0, // Half (Duplicate because of use in encode tests)
Laurence Lundblade492be182025-08-09 09:45:34 -07001275 * 3.140000104904175, // Single XXX
1276 * 0.0, // Single XXX
1277 * NaN, // Single XXX
1278 * Infinity, // Single XXX
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001279 * {100: 0.0, 101: 3.1415926, "euler": 2.718281828459045, 105: 0.0,
1280 * 102: 0.0, 103: 3.141592502593994, "euler2": 2.7182817459106445, 106: 0.0}]
Laurence Lundblade32f3e622020-07-13 20:35:11 -07001281 */
1282static const uint8_t spExpectedFloats[] = {
1283 0x8B,
1284 0xF9, 0x00, 0x00,
1285 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
1286 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1287 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1288 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1289 0xF9, 0x00, 0x00,
1290 0xFA, 0x40, 0x48, 0xF5, 0xC3,
1291 0xFA, 0x00, 0x00, 0x00, 0x00,
1292 0xFA, 0x7F, 0xC0, 0x00, 0x00,
1293 0xFA, 0x7F, 0x80, 0x00, 0x00,
1294 0xA8,
1295 0x18, 0x64,
1296 0xF9, 0x00, 0x00,
1297 0x18, 0x65,
1298 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
1299 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
1300 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
1301 0x18, 0x69,
1302 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1303 0x18, 0x66,
1304 0xF9, 0x00, 0x00,
1305 0x18, 0x67,
1306 0xFA, 0x40, 0x49, 0x0F, 0xDA,
1307 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
1308 0xFA, 0x40, 0x2D, 0xF8, 0x54,
1309 0x18, 0x6A,
1310 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001311
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001312#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001313static const uint8_t spExpectedFloatsNoHalf[] = {
Laurence Lundblade585127a2020-07-15 03:25:24 -07001314 0x8B,
1315 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1316 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
1317 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1318 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1319 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1320 0xFA, 0x00, 0x00, 0x00, 0x00,
1321 0xFA, 0x40, 0x48, 0xF5, 0xC3,
1322 0xFA, 0x00, 0x00, 0x00, 0x00,
1323 0xFA, 0x7F, 0xC0, 0x00, 0x00,
1324 0xFA, 0x7F, 0x80, 0x00, 0x00,
1325 0xA8,
1326 0x18, 0x64,
1327 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1328 0x18, 0x65,
1329 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
1330 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
1331 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
1332 0x18, 0x69,
1333 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1334 0x18, 0x66,
1335 0xFA, 0x00, 0x00, 0x00, 0x00,
1336 0x18, 0x67,
1337 0xFA, 0x40, 0x49, 0x0F, 0xDA,
1338 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
1339 0xFA, 0x40, 0x2D, 0xF8, 0x54,
1340 0x18, 0x6A,
1341 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade32f3e622020-07-13 20:35:11 -07001342
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001343
1344/* Public function. See float_tests.h */
1345int32_t
1346GeneralFloatEncodeTests(void)
Laurence Lundblade32f3e622020-07-13 20:35:11 -07001347{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001348 /* See FloatNumberTests() for tests that really cover lots of float values.
Laurence Lundblade492be182025-08-09 09:45:34 -07001349 * Add new tests for new values or decode modes there.
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001350 * This test is primarily to cover all the float encode methods. */
1351
1352 UsefulBufC Encoded;
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -07001353 UsefulBufC ExpectedFloats;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001354 QCBORError uErr;
1355
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001356#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade32f3e622020-07-13 20:35:11 -07001357 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloats));
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -07001358 ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001359 (void)spExpectedFloatsNoHalf; /* Avoid unused variable error */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001360#else
1361 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloatsNoHalf));
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -07001362 ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloatsNoHalf);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001363 (void)spExpectedFloats; /* Avoid unused variable error */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001364#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade32f3e622020-07-13 20:35:11 -07001365
1366 QCBOREncodeContext EC;
1367 QCBOREncode_Init(&EC, OutBuffer);
1368 QCBOREncode_OpenArray(&EC);
1369
1370 QCBOREncode_AddDouble(&EC, 0.0);
1371 QCBOREncode_AddDouble(&EC, 3.14);
1372 QCBOREncode_AddDoubleNoPreferred(&EC, 0.0);
1373 QCBOREncode_AddDoubleNoPreferred(&EC, NAN);
1374 QCBOREncode_AddDoubleNoPreferred(&EC, INFINITY);
1375
1376 QCBOREncode_AddFloat(&EC, 0.0);
1377 QCBOREncode_AddFloat(&EC, 3.14f);
1378 QCBOREncode_AddFloatNoPreferred(&EC, 0.0f);
1379 QCBOREncode_AddFloatNoPreferred(&EC, NAN);
1380 QCBOREncode_AddFloatNoPreferred(&EC, INFINITY);
1381
1382 QCBOREncode_OpenMap(&EC);
1383
1384 QCBOREncode_AddDoubleToMapN(&EC, 100, 0.0);
1385 QCBOREncode_AddDoubleToMapN(&EC, 101, 3.1415926);
1386 QCBOREncode_AddDoubleToMap(&EC, "euler", 2.71828182845904523536);
1387 QCBOREncode_AddDoubleNoPreferredToMapN(&EC, 105, 0.0);
1388
1389 QCBOREncode_AddFloatToMapN(&EC, 102, 0.0f);
1390 QCBOREncode_AddFloatToMapN(&EC, 103, 3.1415926f);
1391 QCBOREncode_AddFloatToMap(&EC, "euler2", 2.71828182845904523536f);
1392 QCBOREncode_AddFloatNoPreferredToMapN(&EC, 106, 0.0f);
1393
1394 QCBOREncode_CloseMap(&EC);
1395 QCBOREncode_CloseArray(&EC);
1396
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001397 uErr = QCBOREncode_Finish(&EC, &Encoded);
Laurence Lundblade32f3e622020-07-13 20:35:11 -07001398 if(uErr) {
Laurence Lundblade585127a2020-07-15 03:25:24 -07001399 return -1;
Laurence Lundblade32f3e622020-07-13 20:35:11 -07001400 }
1401
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001402 if(UsefulBuf_Compare(Encoded, ExpectedFloats)) {
Laurence Lundblade585127a2020-07-15 03:25:24 -07001403 return -3;
Laurence Lundblade32f3e622020-07-13 20:35:11 -07001404 }
1405
1406 return 0;
1407}
1408
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001409#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001410
1411
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001412/* Public function. See float_tests.h */
Laurence Lundblade492be182025-08-09 09:45:34 -07001413int32_t
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001414GeneralFloatDecodeTests(void)
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001415{
Laurence Lundblade492be182025-08-09 09:45:34 -07001416 /* See FloatNumberTests() for tests that really covers the float values.
1417 * This is retained to cover GetDouble() and decode of a single 0 */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001418
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001419 QCBORItem Item;
1420 QCBORError uErr;
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001421 QCBORDecodeContext DC;
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001422 UsefulBufC TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
1423 QCBORDecode_Init(&DC, TestData, 0);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001424
1425 QCBORDecode_GetNext(&DC, &Item);
1426 if(Item.uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001427 return MakeTestResultCode(0, 1, 0);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001428 }
1429
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001430 /* 0.0 half-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001431 uErr = QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade492be182025-08-09 09:45:34 -07001432 if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS)
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001433#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1434 || Item.uDataType != QCBOR_TYPE_DOUBLE
1435 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001436#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
1437 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001438#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
1439 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001440 return MakeTestResultCode(0, 2, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001441 }
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001442
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001443 /* 3.14 double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001444 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001445 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1446#ifndef USEFULBUF_DISABLE_ALL_FLOAT
1447 || Item.uDataType != QCBOR_TYPE_DOUBLE
1448 || Item.val.dfnum != 3.14
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001449#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1450 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001451#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1452 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001453 return MakeTestResultCode(0, 3, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001454 }
1455
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001456 /* 0.0 double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001457 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001458 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1459#ifndef USEFULBUF_DISABLE_ALL_FLOAT
1460 || Item.uDataType != QCBOR_TYPE_DOUBLE
1461 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001462#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1463 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001464#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1465 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001466 return MakeTestResultCode(0, 4, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001467 }
1468
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001469 /* NaN double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001470 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001471 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1472#ifndef USEFULBUF_DISABLE_ALL_FLOAT
1473 || Item.uDataType != QCBOR_TYPE_DOUBLE
1474 || !isnan(Item.val.dfnum)
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001475#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1476 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001477#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1478 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001479 return MakeTestResultCode(0, 5, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001480 }
1481
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001482 /* Infinity double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001483 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001484 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1485#ifndef USEFULBUF_DISABLE_ALL_FLOAT
1486 || Item.uDataType != QCBOR_TYPE_DOUBLE
1487 || Item.val.dfnum != INFINITY
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001488#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1489 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001490#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1491 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001492 return MakeTestResultCode(0, 6, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001493 }
1494
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001495 /* 0.0 half-precision (again) */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001496 uErr = QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade492be182025-08-09 09:45:34 -07001497 if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS)
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001498#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1499 || Item.uDataType != QCBOR_TYPE_DOUBLE
1500 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001501#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1502 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001503#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
1504 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001505 return MakeTestResultCode(0, 7, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001506 }
1507
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001508 /* 3.140000104904175 single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001509 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001510 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1511#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade492be182025-08-09 09:45:34 -07001512#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001513 || Item.uDataType != QCBOR_TYPE_DOUBLE
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001514 || 3.1400001049041748 != Item.val.dfnum
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001515#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001516 || Item.uDataType != QCBOR_TYPE_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001517 || 3.140000f != Item.val.fnum
Laurence Lundblade492be182025-08-09 09:45:34 -07001518#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001519#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1520 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001521#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1522 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001523 return MakeTestResultCode(0, 8, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001524 }
1525
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001526 /* 0.0 single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001527 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001528 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1529#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade492be182025-08-09 09:45:34 -07001530#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001531 || Item.uDataType != QCBOR_TYPE_DOUBLE
1532 || Item.val.dfnum != 0.0
1533#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001534 || Item.uDataType != QCBOR_TYPE_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001535 || Item.val.fnum != 0.0f
Laurence Lundblade492be182025-08-09 09:45:34 -07001536#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001537#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1538 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001539#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1540 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001541 return MakeTestResultCode(0, 9, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001542 }
1543
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001544 /* NaN single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001545 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001546 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1547#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade492be182025-08-09 09:45:34 -07001548#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001549 || Item.uDataType != QCBOR_TYPE_DOUBLE
1550 || !isnan(Item.val.dfnum)
Laurence Lundblade492be182025-08-09 09:45:34 -07001551#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001552 || Item.uDataType != QCBOR_TYPE_FLOAT
1553 || !isnan(Item.val.fnum)
Laurence Lundblade492be182025-08-09 09:45:34 -07001554#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001555#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1556 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001557#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1558 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001559 return MakeTestResultCode(0, 10, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001560 }
1561
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001562 /* Infinity single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001563 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001564 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1565#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade492be182025-08-09 09:45:34 -07001566#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001567 || Item.uDataType != QCBOR_TYPE_DOUBLE
1568 || Item.val.dfnum != INFINITY
Laurence Lundblade492be182025-08-09 09:45:34 -07001569#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001570 || Item.uDataType != QCBOR_TYPE_FLOAT
1571 || Item.val.fnum != INFINITY
Laurence Lundblade492be182025-08-09 09:45:34 -07001572#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001573#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1574 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001575#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1576 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001577 return MakeTestResultCode(0, 11, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001578 }
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001579 /* Sufficent test coverage. Don't need to decode the rest. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001580
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001581
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001582#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001583 /* Now tests for spiffy decode main function */
1584 TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001585 double d;
1586 QCBORDecode_Init(&DC, TestData, 0);
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07001587 QCBORDecode_EnterArray(&DC, NULL);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001588
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001589 /* 0.0 half-precision */
1590 QCBORDecode_GetDouble(&DC, &d);
1591 uErr = QCBORDecode_GetAndResetError(&DC);
Laurence Lundblade492be182025-08-09 09:45:34 -07001592 if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001593#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001594 || d != 0.0
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001595#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001596 ) {
1597 return MakeTestResultCode(1, 1, uErr);
1598 }
1599
1600 /* 3.14 double-precision */
1601 QCBORDecode_GetDouble(&DC, &d);
1602 uErr = QCBORDecode_GetAndResetError(&DC);
1603 if(uErr != QCBOR_SUCCESS || d != 3.14) {
1604 return MakeTestResultCode(1, 2, uErr);
1605 }
1606
1607 /* 0.0 double-precision */
1608 QCBORDecode_GetDouble(&DC, &d);
1609 uErr = QCBORDecode_GetAndResetError(&DC);
1610 if(uErr != QCBOR_SUCCESS || d != 0.0) {
1611 return MakeTestResultCode(1, 3, uErr);
1612 }
1613
1614 /* NaN double-precision */
1615 QCBORDecode_GetDouble(&DC, &d);
1616 uErr = QCBORDecode_GetAndResetError(&DC);
1617 if(uErr != QCBOR_SUCCESS || !isnan(d)) {
1618 return MakeTestResultCode(1, 4, uErr);
1619 }
1620
1621 /* Infinity double-precision */
1622 QCBORDecode_GetDouble(&DC, &d);
1623 uErr = QCBORDecode_GetAndResetError(&DC);
1624 if(uErr != QCBOR_SUCCESS || d != INFINITY) {
1625 return MakeTestResultCode(1, 5, uErr);
1626 }
1627
1628 /* 0.0 half-precision */
1629 QCBORDecode_GetDouble(&DC, &d);
1630 uErr = QCBORDecode_GetAndResetError(&DC);
Laurence Lundblade492be182025-08-09 09:45:34 -07001631 if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS)
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001632#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1633 || d != 0.0
1634#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
1635 ) {
1636 return MakeTestResultCode(1, 6, uErr);
1637 }
1638
1639 /* 3.140000104904175 single-precision */
1640 QCBORDecode_GetDouble(&DC, &d);
1641 uErr = QCBORDecode_GetAndResetError(&DC);
Laurence Lundblade492be182025-08-09 09:45:34 -07001642 if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS) /* Different in 2.0 and 1.6 */
1643#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001644 || d != 3.140000104904175
Laurence Lundblade492be182025-08-09 09:45:34 -07001645#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001646 ) {
1647 return MakeTestResultCode(1, 7, uErr);
1648 }
1649
1650 /* 0.0 single-precision */
1651 QCBORDecode_GetDouble(&DC, &d);
1652 uErr = QCBORDecode_GetAndResetError(&DC);
Laurence Lundblade492be182025-08-09 09:45:34 -07001653 if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS) /* Different in 2.0 and 1.6 */
1654#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001655 || d != 0.0
Laurence Lundblade492be182025-08-09 09:45:34 -07001656#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001657 ) {
1658 return MakeTestResultCode(1, 8, uErr);
1659 }
1660
1661 /* NaN single-precision */
1662 QCBORDecode_GetDouble(&DC, &d);
Laurence Lundblade492be182025-08-09 09:45:34 -07001663 if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS) /* Different in 2.0 and 1.6 */
1664#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001665 || !isnan(d)
Laurence Lundblade492be182025-08-09 09:45:34 -07001666#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001667 ) {
1668 return MakeTestResultCode(1, 9, uErr);
1669 }
1670
1671 /* Infinity single-precision */
1672 QCBORDecode_GetDouble(&DC, &d);
1673 uErr = QCBORDecode_GetAndResetError(&DC);
Laurence Lundblade492be182025-08-09 09:45:34 -07001674 if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS) /* Different in 2.0 and 1.6 */
1675#ifndef QCBOR_DISABLQCBOR_DISABLE_PREFERRED_FLOATE_FLOAT_HW_USE
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001676 || d != INFINITY
Laurence Lundblade492be182025-08-09 09:45:34 -07001677#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001678 ) {
1679 return MakeTestResultCode(1, 10, uErr);
1680 }
1681
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001682#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001683 return 0;
1684}
1685