blob: 6e00472a00326793131d9b355ce24a309a12fb5a [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 *
4 * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved.
5 * Copyright (c) 2021, Arm Limited. All rights reserved.
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
Laurence Lundblade4903e552024-08-21 11:13:48 -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 Lundblade585127a2020-07-15 03:25:24 -070016#include "qcbor/qcbor_encode.h"
Laurence Lundblade02fcf312020-07-17 02:49:46 -070017#include "qcbor/qcbor_decode.h"
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -070018#include "qcbor/qcbor_spiffy_decode.h"
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070019#include <math.h> /* For INFINITY and NAN and isnan() */
Laurence Lundblade585127a2020-07-15 03:25:24 -070020
Laurence Lundblade16a207a2021-09-18 17:22:46 -070021
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070022
23/* Make a test results code that includes three components. Return code
24 * is xxxyyyzzz where zz is the error code, yy is the test number and
25 * zz is check being performed
Laurence Lundblade16a207a2021-09-18 17:22:46 -070026 */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070027static inline int32_t
28MakeTestResultCode(uint32_t uTestCase,
29 uint32_t uTestNumber,
30 QCBORError uErrorCode)
Laurence Lundblade16a207a2021-09-18 17:22:46 -070031{
32 uint32_t uCode = (uTestCase * 1000000) +
33 (uTestNumber * 1000) +
34 (uint32_t)uErrorCode;
35 return (int32_t)uCode;
36}
37
38
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -070039#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade9682a532020-06-06 18:33:04 -070040
Laurence Lundbladed711fb22018-09-26 14:35:22 -070041#include "half_to_double_from_rfc7049.h"
Laurence Lundblade68a13352018-09-23 02:19:54 -070042
Laurence Lundblade2d85ce42018-10-12 14:12:47 +080043
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070044struct DoubleTestCase {
45 double dNumber;
46 double fNumber;
47 UsefulBufC Preferred;
48 UsefulBufC NotPreferred;
49 UsefulBufC CDE;
50 UsefulBufC DCBOR;
51};
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -070052
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070053/* Boundaries for all destination conversions to test at.
54 *
55 * smallest subnormal single 1.401298464324817e-45 2^^-149
56 * largest subnormal single 1.1754942106924411e-38 2^^-126
57 * smallest normal single 1.1754943508222875e-38
58 * largest single 3.4028234663852886E+38
59 *
60 * smallest subnormal half 5.9604644775390625E-8
61 * largest subnormal half 6.097555160522461E-5
62 * smallest normal half 6.103515625E-5
63 * largest half 65504.0
64 *
65 * Boundaries for origin conversions
66 * smallest subnormal double 5.0e-324 2^^-1074
67 * largest subnormal double
68 * smallest normal double 2.2250738585072014e-308 2^^-1022
69 * largest normal double 1.7976931348623157e308 2^^-1023
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070070 */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070071
72/* Always four lines per test case so shell scripts can process into
73 * other formats. CDE and DCBOR standards are not complete yet,
74 * encodings are a guess. C string literals are used because they
75 * are the shortest notation. They are used __with a length__ . Null
Laurence Lundblade475c2722024-05-08 11:17:47 -070076 * termination doesn't work because there are zero bytes.
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070077 */
78static const struct DoubleTestCase DoubleTestCases[] = {
79 /* Zero */
80 {0.0, 0.0f,
81 {"\xF9\x00\x00", 3}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x00", 9},
82 {"\xF9\x00\x00", 3}, {"\xF9\x00\x00", 3}},
83
84 /* Negative Zero */
85 {-0.0, -0.0f,
86 {"\xF9\x80\x00", 3}, {"\xFB\x80\x00\x00\x00\x00\x00\x00\x00", 9},
87 {"\xF9\x80\x00", 3}, {"\xF9\x80\x00", 3}},
88
89 /* NaN */
90 {NAN, NAN,
91 {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9},
92 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
93
94 /* Infinity */
95 {INFINITY, INFINITY,
96 {"\xF9\x7C\x00", 3}, {"\xFB\x7F\xF0\x00\x00\x00\x00\x00\x00", 9},
97 {"\xF9\x7C\x00", 3}, {"\xF9\x7C\x00", 3}},
98
99 /* Negative Infinity */
100 {-INFINITY, -INFINITY,
101 {"\xF9\xFC\x00", 3}, {"\xFB\xFF\xF0\x00\x00\x00\x00\x00\x00", 9},
102 {"\xF9\xFC\x00", 3}, {"\xF9\xFC\x00", 3}},
103
104 /* 1.0 */
105 {1.0, 1.0f,
106 {"\xF9\x3C\x00", 3}, {"\xFB\x3F\xF0\x00\x00\x00\x00\x00\x00", 9},
107 {"\xF9\x3C\x00", 3}, {"\xF9\x3C\x00", 3}},
108
109 /* -2.0 -- a negative number that is not zero */
110 {-2.0, -2.0f,
111 {"\xF9\xC0\x00", 3}, {"\xFB\xC0\x00\x00\x00\x00\x00\x00\x00", 9},
112 {"\xF9\xC0\x00", 3}, {"\xF9\x3C\x00", 3}},
113
114 /* 1/3 */
115 {0.333251953125, 0.333251953125f,
116 {"\xF9\x35\x55", 3}, {"\xFB\x3F\xD5\x54\x00\x00\x00\x00\x00", 9},
117 {"\xF9\x35\x55", 3}, {"\xF9\x35\x55", 3}},
118
119 /* 5.9604644775390625E-8 -- smallest half-precision subnormal */
120 {5.9604644775390625E-8, 0.0f,
121 {"\xF9\x00\x01", 3}, {"\xFB\x3E\x70\x00\x00\x00\x00\x00\x00", 9},
122 {"\xF9\x00\x01", 3}, {"\xF9\x00\x01", 3}},
123
124 /* 3.0517578125E-5 -- a half-precision subnormal */
125 {3.0517578125E-5, 0.0f,
126 {"\xF9\x02\x00", 3}, {"\xFB\x3F\x00\x00\x00\x00\x00\x00\x00", 9},
127 {"\xF9\x02\x00", 3}, {"\xF9\x02\x00", 3}},
128
129 /* 6.097555160522461E-5 -- largest half-precision subnormal */
130 {6.097555160522461E-5, 0.0f,
131 {"\xF9\x03\xFF", 3}, {"\xFB\x3F\x0F\xF8\x00\x00\x00\x00\x00", 9},
132 {"\xF9\x03\xFF", 3}, {"\xF9\04\00", 3}},
133
134 /* 6.103515625E-5 -- smallest possible half-precision normal */
135 {6.103515625E-5, 0.0f,
136 {"\xF9\04\00", 3}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x00", 9},
137 {"\xF9\04\00", 3}, {"\xF9\04\00", 3}},
138
139 /* 6.1035156250000014E-5 -- slightly larger than smallest half-precision normal */
140 {6.1035156250000014E-5, 6.1035156250000014E-5f,
141 {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9},
142 {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}},
143
144 /* 6.1035156249999993E-5 -- slightly smaller than smallest half-precision normal */
145 {6.1035156249999993E-5, 0.0f,
146 {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
147 {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
148
149 /* 65504.0 -- largest possible half-precision */
150 {65504.0, 0.0f,
151 {"\xF9\x7B\xFF", 3}, {"\xFB\x40\xEF\xFC\x00\x00\x00\x00\x00", 9},
152 {"\xF9\x7B\xFF", 3}, {"\xF9\x7B\xFF", 3}},
153
154 /* 65504.1 -- exponent too large and too much precision to convert */
155 {65504.1, 0.0f,
156 {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9},
157 {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}},
158
159 /* 65536.0 -- exponent too large but not too much precision for single */
160 {65536.0, 65536.0f,
161 {"\xFA\x47\x80\x00\x00", 5}, {"\xFB\x40\xF0\x00\x00\x00\x00\x00\x00", 9},
162 {"\xFA\x47\x80\x00\x00", 5}, {"\xFA\x47\x80\x00\x00", 5}},
163
164 /* 1.401298464324817e-45 -- smallest single subnormal */
165 {1.401298464324817e-45, 1.40129846E-45f,
166 {"\xFA\x00\x00\x00\x01", 5}, {"\xFB\x36\xA0\x00\x00\x00\x00\x00\x00", 9},
167 {"\xFA\x00\x00\x00\x01", 5}, {"\xFA\x00\x00\x00\x01", 5}},
168
169 /* 5.8774717541114375E-39 -- slightly smaller than the smallest
170 // single normal */
171 {5.8774717541114375E-39, 5.87747175E-39f,
172 {"\xFA\x00\x40\x00\x00", 5}, {"\xFB\x38\x00\x00\x00\x00\x00\x00\x00", 9},
173 {"\xFA\x00\x40\x00\x00", 5}, {"\xFA\x00\x40\x00\x00", 5}},
174
175 /* 1.1754942106924411e-38 -- largest single subnormal */
176 {1.1754942106924411E-38, 1.17549421E-38f,
177 {"\xFA\x00\x7f\xff\xff", 5}, {"\xFB\x38\x0f\xff\xff\xC0\x00\x00\x00", 9},
178 {"\xFA\x00\x7f\xff\xff", 5}, {"\xFA\x00\x7f\xff\xff", 5} },
179
180 /* 1.1754943508222874E-38 -- slightly bigger than smallest single normal */
181 {1.1754943508222874E-38, 0.0f,
182 {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9},
183 {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}},
184
185 /* 1.1754943508222875e-38 -- smallest single normal */
186 {1.1754943508222875e-38, 1.17549435E-38f,
187 {"\xFA\x00\x80\x00\x00", 5}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x00", 9},
188 {"\xFA\x00\x80\x00\x00", 5}, {"\xFA\x00\x80\x00\x00", 5}},
189
190 /* 1.1754943508222875e-38 -- slightly bigger than smallest single normal */
191 {1.1754943508222878e-38, 0.0f,
192 {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9},
193 {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}},
194
195 /* 16777216 -- converts to single without loss */
196 {16777216, 16777216,
197 {"\xFA\x4B\x80\x00\x00", 5}, {"\xFB\x41\x70\x00\x00\x00\x00\x00\x00", 9},
198 {"\xFA\x4B\x80\x00\x00", 5}, {"\xFA\x4B\x80\x00\x00", 5}},
199
200 /* 16777217 -- one more than above and fails conversion to single */
201 {16777217, 16777216,
202 {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9},
203 {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}},
204
205 /* 3.4028234663852886E+38 -- largest possible single normal */
206 {3.4028234663852886E+38, 3.40282347E+38f,
207 {"\xFA\x7F\x7F\xFF\xFF", 5}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
208 {"\xFA\x7F\x7F\xFF\xFF", 5}, {"\xFA\x7F\x7F\xFF\xFF", 5}},
209
210 /* 3.402823466385289E+38 -- slightly larger than largest possible single */
211 {3.402823466385289E+38, 0.0f,
212 {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9},
213 {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}},
214
215 /* 3.402823669209385e+38 -- exponent larger by one than largest possible single */
216 {3.402823669209385e+38, 0.0f,
217 {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9},
218 {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}},
219
220 /* 5.0e-324 -- smallest double subnormal normal */
221 {5.0e-324, 0.0f,
222 {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9},
223 {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}},
224
225 /* 2.2250738585072009E−308 -- largest double subnormal */
226 {2.2250738585072009e-308, 0.0f,
227 {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
228 {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
229
230 /* 2.2250738585072014e-308 -- smallest double normal */
231 {2.2250738585072014e-308, 0.0f,
232 {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9},
233 {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}},
234
235 /* 1.7976931348623157E308 -- largest double normal */
236 {1.7976931348623157e308, 0.0f,
237 {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
238 {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
239
240 /* List terminator */
241 {0.0, 0.0f, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700242};
243
244
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700245struct NaNTestCase {
246 uint64_t uDouble;
247 uint32_t uSingle;
248 UsefulBufC Preferred;
249 UsefulBufC NotPreferred;
250 UsefulBufC CDE;
251 UsefulBufC DCBOR;
252};
253
254/* Always four lines per test case so shell scripts can process into
255 * other formats. CDE and DCBOR standards are not complete yet,
256 * encodings are a guess. C string literals are used because they
257 * are the shortest notation. They are used __with a length__ . Null
258 * termination doesn't work because there are zero bytes.
259 */
260static const struct NaNTestCase NaNTestCases[] = {
261
262 /* Payload with most significant bit set, a qNaN by most implementations */
263 {0x7ff8000000000000, 0x00000000,
264 {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9},
265 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
266
267 /* Payload with single rightmost set */
268 {0x7ff8000000000001, 0x00000000,
269 {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x01", 9},
270 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
271
272 /* Payload with 10 leftmost bits set -- converts to half */
273 {0x7ffffc0000000000, 0x00000000,
274 {"\xF9\x7F\xFF", 3}, {"\xFB\x7F\xFF\xFC\x00\x00\x00\x00\x00", 9},
275 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
276
277 /* Payload with 10 rightmost bits set -- cannot convert to half */
278 {0x7ff80000000003ff, 0x00000000,
279 {"\xFB\x7F\xF8\x00\x00\x00\x00\x03\xFF", 9}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x03\xFF", 9},
280 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
281
282 /* Payload with 23 leftmost bits set -- converts to a single */
283 {0x7ffFFFFFE0000000, 0x7fffffff,
284 {"\xFA\x7F\xFF\xFF\xFF", 5}, {"\xFB\x7F\xFF\xFF\xFF\xE0\x00\x00\x00", 9},
285 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
286
287 /* Payload with 24 leftmost bits set -- fails to convert to a single */
288 {0x7ffFFFFFF0000000, 0x00000000,
289 {"\xFB\x7F\xFF\xFF\xFF\xF0\x00\x00\x00", 9}, {"\xFB\x7F\xFF\xFF\xFF\xF0\x00\x00\x00", 9},
290 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
291
292 /* Payload with all bits set */
293 {0x7fffffffffffffff, 0x00000000,
294 {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
295 {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
296
297 /* List terminator */
298 {0, 0, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} }
299};
300
301
302
303/* Public function. See float_tests.h
304 *
305 * This is the main test of floating-point encoding / decoding. It is
306 * data-driven by the above tables. It works better than tests below that
307 * it mostly replaces because it tests one number at a time, rather than
308 * putting them all in a map. It is much easier to debug test failures
309 * and to add new tests. */
310int32_t
311FloatValuesTests(void)
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700312{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700313 unsigned int uTestIndex;
314 const struct DoubleTestCase *pTestCase;
315 const struct NaNTestCase *pNaNTestCase;
316 MakeUsefulBufOnStack( TestOutBuffer, 20);
317 UsefulBufC TestOutput;
318 QCBOREncodeContext EnCtx;
319 QCBORError uErr;
320 QCBORDecodeContext DCtx;
321 QCBORItem Item;
322 uint64_t uDecoded;
323#ifdef QCBOR_DISABLE_FLOAT_HW_USE
324 uint32_t uDecoded2;
325#endif
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700326
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700327 /* Test a variety of doubles */
328 for(uTestIndex = 0; DoubleTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
329 pTestCase = &DoubleTestCases[uTestIndex];
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700330
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700331 // if(pTestCase->dNumber == 1.1754943508222874E-38) {
332 if(uTestIndex == 19) {
333 uErr = 99; /* For setting break points for particular tests */
334 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800335
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700336 /* Number Encode of Preferred */
337 QCBOREncode_Init(&EnCtx, TestOutBuffer);
338 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
339 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800340
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700341 if(uErr != QCBOR_SUCCESS) {
342 return MakeTestResultCode(uTestIndex, 1, uErr);;
343 }
344 if(UsefulBuf_Compare(TestOutput, pTestCase->Preferred)) {
345 return MakeTestResultCode(uTestIndex, 1, 200);
346 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700347
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700348 /* Number Encode of Not Preferred */
349 QCBOREncode_Init(&EnCtx, TestOutBuffer);
350 QCBOREncode_AddDoubleNoPreferred(&EnCtx, pTestCase->dNumber);
351 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
Laurence Lundblade68a13352018-09-23 02:19:54 -0700352
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700353 if(uErr != QCBOR_SUCCESS) {
354 return MakeTestResultCode(uTestIndex, 2, uErr);;
355 }
356 if(UsefulBuf_Compare(TestOutput, pTestCase->NotPreferred)) {
357 return MakeTestResultCode(uTestIndex, 2, 200);
358 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800359
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700360 /* Number Decode of Preferred */
361 QCBORDecode_Init(&DCtx, pTestCase->Preferred, 0);
362 uErr = QCBORDecode_GetNext(&DCtx, &Item);
363 if(uErr != QCBOR_SUCCESS) {
364 return MakeTestResultCode(uTestIndex, 3, uErr);;
365 }
366#ifndef QCBOR_DISABLE_FLOAT_HW_USE
367 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
368 return MakeTestResultCode(uTestIndex, 4, 0);
369 }
370 if(isnan(pTestCase->dNumber)) {
371 if(!isnan(Item.val.dfnum)) {
372 return MakeTestResultCode(uTestIndex, 5, 0);
373 }
374 } else {
375 if(Item.val.dfnum != pTestCase->dNumber) {
376 return MakeTestResultCode(uTestIndex, 6, 0);
377 }
378 }
379#else /* QCBOR_DISABLE_FLOAT_HW_USE */
380 /* When QCBOR_DISABLE_FLOAT_HW_USE is set, single-precision is not
381 * converted to double when decoding, so test differently. len == 5
382 * indicates single-precision in the encoded CBOR. */
383 if(pTestCase->Preferred.len == 5) {
384 if(Item.uDataType != QCBOR_TYPE_FLOAT) {
385 return MakeTestResultCode(uTestIndex, 4, 0);
386 }
387 if(isnan(pTestCase->dNumber)) {
388 if(!isnan(Item.val.fnum)) {
389 return MakeTestResultCode(uTestIndex, 5, 0);
390 }
391 } else {
392 if(Item.val.fnum != pTestCase->fNumber) {
393 return MakeTestResultCode(uTestIndex, 6, 0);
394 }
395 }
396 } else {
397 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
398 return MakeTestResultCode(uTestIndex, 4, 0);
399 }
400 if(isnan(pTestCase->dNumber)) {
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700401 if(!isnan(Item.val.dfnum)) {
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700402 return MakeTestResultCode(uTestIndex, 5, 0);
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700403 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700404 } else {
405 if(Item.val.dfnum != pTestCase->dNumber) {
406 return MakeTestResultCode(uTestIndex, 6, 0);
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700407 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700408 }
409 }
410#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700411
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700412 /* Number Decode of Not Preferred */
413 QCBORDecode_Init(&DCtx, pTestCase->NotPreferred, 0);
414 uErr = QCBORDecode_GetNext(&DCtx, &Item);
415 if(uErr != QCBOR_SUCCESS) {
416 return MakeTestResultCode(uTestIndex, 7, uErr);;
417 }
418 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
419 return MakeTestResultCode(uTestIndex, 8, 0);
420 }
421 if(isnan(pTestCase->dNumber)) {
422 if(!isnan(Item.val.dfnum)) {
423 return MakeTestResultCode(uTestIndex, 9, 0);
424 }
425 } else {
426 if(Item.val.dfnum != pTestCase->dNumber) {
427 return MakeTestResultCode(uTestIndex, 10, 0);
428 }
429 }
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700430
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700431 }
432
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700433 /* Test a variety of NaNs with payloads */
434 for(uTestIndex = 0; NaNTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
435 pNaNTestCase = &NaNTestCases[uTestIndex];
436
437
438 if(uTestIndex == 4) {
439 uErr = 99; /* For setting break points for particular tests */
440 }
441
442 /* NaN Encode of Preferred */
443 QCBOREncode_Init(&EnCtx, TestOutBuffer);
444 QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
445 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
446 if(uErr != QCBOR_SUCCESS) {
447 return MakeTestResultCode(uTestIndex+100, 10, uErr);;
448 }
449 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) {
450 return MakeTestResultCode(uTestIndex+100, 10, 200);
451 }
452
453#ifdef QCBOR_COMPARE_TO_HW_NAN_CONVERSION
454 {
455 /* This test is off by default. It's purpose is to check
456 * QCBOR's mask-n-shift implementation against the HW/CPU
457 * instructions that do conversion between double and single.
458 * It is off because it is only used on occasion to verify
459 * QCBOR and because it is suspected that some HW/CPU does
460 * implement this correctly. NaN payloads are an obscure
461 * feature. */
462 float f;
463 double d, d2;
464
465 d = UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uNumber);
466
467 /* Cast the double to a single and then back to a double and
468 * see if they are equal. If so, then the NaN payload doesn't
469 * have any bits that are lost when converting to single and
470 * it can be safely converted.
471 *
472 * This test can't be done for half-precision because it is
473 * not widely supported.
474 */
475 f = (float)d;
476 d2 = (double)f;
477
478 /* The length of encoded doubles is 9, singles 5 and halves
479 * 3. If there are NaN payload bits that can't be converted,
480 * then the length must be 9.
481 */
482 if((uint64_t)d != (uint64_t)d2 && pNaNTestCase->Preferred.len != 9) {
483 /* QCBOR conversion not the same as HW conversion */
484 return MakeTestResultCode(uTestIndex, 9, 200);
485 }
486 }
487#endif /* QCBOR_COMPARE_TO_HW_NAN_CONVERSION */
488
489
490 /* NaN Encode of Not Preferred */
491 QCBOREncode_Init(&EnCtx, TestOutBuffer);
492 QCBOREncode_AddDoubleNoPreferred(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
493 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
494 if(uErr != QCBOR_SUCCESS) {
495 return MakeTestResultCode(uTestIndex+100, 11, uErr);;
496 }
497 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
498 return MakeTestResultCode(uTestIndex+100, 11, 200);
499 }
500
501 /* NaN Decode of Preferred */
502 QCBORDecode_Init(&DCtx, pNaNTestCase->Preferred, 0);
503 uErr = QCBORDecode_GetNext(&DCtx, &Item);
504 if(uErr != QCBOR_SUCCESS) {
505 return MakeTestResultCode(uTestIndex+100, 12, uErr);
506 }
507
508#ifndef QCBOR_DISABLE_FLOAT_HW_USE
509
510 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
511 if(uDecoded != pNaNTestCase->uDouble) {
512 return MakeTestResultCode(uTestIndex+100, 12, 200);
513 }
514#else /* QCBOR_DISABLE_FLOAT_HW_USE */
515 if(pNaNTestCase->Preferred.len == 5) {
516 if(Item.uDataType != QCBOR_TYPE_FLOAT) {
517 return MakeTestResultCode(uTestIndex, 4, 0);
518 }
519
520 uDecoded2 = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum);
521
522 if(uDecoded2 != pNaNTestCase->uSingle) {
523 return MakeTestResultCode(uTestIndex, 4, 0);
524 }
525 } else {
526 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
527 return MakeTestResultCode(uTestIndex, 4, 0);
528 }
529 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
530 if(uDecoded != pNaNTestCase->uDouble) {
531 return MakeTestResultCode(uTestIndex+100, 12, 200);
532 }
533 }
534#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
535
536 /* NaN Decode of Not Preferred */
537 QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0);
538 uErr = QCBORDecode_GetNext(&DCtx, &Item);
539 if(uErr != QCBOR_SUCCESS) {
540 return MakeTestResultCode(uTestIndex+100, 13, uErr);
541 }
542 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
543 if(uDecoded != pNaNTestCase->uDouble) {
544 return MakeTestResultCode(uTestIndex+100, 13, 200);
545 }
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700546 }
547
548 return 0;
Laurence Lundblade570fab52018-10-13 18:28:27 +0800549}
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700550
551
552
553/* Public function. See float_tests.h */
554int32_t
555HalfPrecisionAgainstRFCCodeTest(void)
556{
557 QCBORItem Item;
558 QCBORDecodeContext DC;
559 unsigned char pbHalfBytes[2];
560 uint8_t uHalfPrecInitialByte;
561 double d;
562 UsefulBuf_MAKE_STACK_UB(EncodedBytes, 3);
563 UsefulOutBuf UOB;
564 uint32_t uHalfP;
565
566
567 for(uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
568 pbHalfBytes[1] = (uint8_t)(uHalfP & 0xff);
569 pbHalfBytes[0] = (uint8_t)(uHalfP >> 8); /* uHalfP is always less than 0xffff */
570 d = decode_half(pbHalfBytes);
571
572 /* Construct the CBOR for the half-precision float by hand */
573 UsefulOutBuf_Init(&UOB, EncodedBytes);
574
575 uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); /* 0xf9 */
576 UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); /* initial byte */
577 UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP); /* argument */
578
579 /* Now parse the hand-constructed CBOR. This will invoke the
580 * conversion to a float
581 */
582 QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
583 QCBORDecode_GetNext(&DC, &Item);
584 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
585 return -1;
586 }
587
588 if(isnan(d)) {
589 /* The RFC code uses the native instructions which may or may not
590 * handle sNaN, qNaN and NaN payloads correctly. This test just
591 * makes sure it is a NaN and doesn't worry about the type of NaN
592 */
593 if(!isnan(Item.val.dfnum)) {
594 return -3;
595 }
596 } else {
597 if(Item.val.dfnum != d) {
598 return -2;
599 }
600 }
601 }
602 return 0;
603}
604
Laurence Lundblade585127a2020-07-15 03:25:24 -0700605#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700606
607
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700608/*
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700609 * Some encoded floating point numbers that are used for both
610 * encode and decode tests.
611 *
612 * [0.0, // Half
613 * 3.14, // Double
614 * 0.0, // Double
615 * NaN, // Double
616 * Infinity, // Double
617 * 0.0, // Half (Duplicate because of use in encode tests)
618 * 3.140000104904175, // Single
619 * 0.0, // Single
620 * NaN, // Single
621 * Infinity, // Single
622 * {100: 0.0, 101: 3.1415926, "euler": 2.718281828459045, 105: 0.0,
623 * 102: 0.0, 103: 3.141592502593994, "euler2": 2.7182817459106445, 106: 0.0}]
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700624 */
625static const uint8_t spExpectedFloats[] = {
626 0x8B,
627 0xF9, 0x00, 0x00,
628 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
629 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
630 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
631 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
632 0xF9, 0x00, 0x00,
633 0xFA, 0x40, 0x48, 0xF5, 0xC3,
634 0xFA, 0x00, 0x00, 0x00, 0x00,
635 0xFA, 0x7F, 0xC0, 0x00, 0x00,
636 0xFA, 0x7F, 0x80, 0x00, 0x00,
637 0xA8,
638 0x18, 0x64,
639 0xF9, 0x00, 0x00,
640 0x18, 0x65,
641 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
642 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
643 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
644 0x18, 0x69,
645 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
646 0x18, 0x66,
647 0xF9, 0x00, 0x00,
648 0x18, 0x67,
649 0xFA, 0x40, 0x49, 0x0F, 0xDA,
650 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
651 0xFA, 0x40, 0x2D, 0xF8, 0x54,
652 0x18, 0x6A,
653 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700654
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200655#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700656static const uint8_t spExpectedFloatsNoHalf[] = {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700657 0x8B,
658 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
659 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
660 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
661 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
662 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
663 0xFA, 0x00, 0x00, 0x00, 0x00,
664 0xFA, 0x40, 0x48, 0xF5, 0xC3,
665 0xFA, 0x00, 0x00, 0x00, 0x00,
666 0xFA, 0x7F, 0xC0, 0x00, 0x00,
667 0xFA, 0x7F, 0x80, 0x00, 0x00,
668 0xA8,
669 0x18, 0x64,
670 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
671 0x18, 0x65,
672 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
673 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
674 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
675 0x18, 0x69,
676 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
677 0x18, 0x66,
678 0xFA, 0x00, 0x00, 0x00, 0x00,
679 0x18, 0x67,
680 0xFA, 0x40, 0x49, 0x0F, 0xDA,
681 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
682 0xFA, 0x40, 0x2D, 0xF8, 0x54,
683 0x18, 0x6A,
684 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700685
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700686
687/* Public function. See float_tests.h */
688int32_t
689GeneralFloatEncodeTests(void)
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700690{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700691 /* See FloatNumberTests() for tests that really cover lots of float values.
692 * Add new tests for new values or decode modes there.
693 * This test is primarily to cover all the float encode methods. */
694
695 UsefulBufC Encoded;
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700696 UsefulBufC ExpectedFloats;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700697 QCBORError uErr;
698
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700699#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700700 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloats));
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700701 ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700702 (void)spExpectedFloatsNoHalf; /* Avoid unused variable error */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700703#else
704 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloatsNoHalf));
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700705 ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloatsNoHalf);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700706 (void)spExpectedFloats; /* Avoid unused variable error */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700707#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700708
709 QCBOREncodeContext EC;
710 QCBOREncode_Init(&EC, OutBuffer);
711 QCBOREncode_OpenArray(&EC);
712
713 QCBOREncode_AddDouble(&EC, 0.0);
714 QCBOREncode_AddDouble(&EC, 3.14);
715 QCBOREncode_AddDoubleNoPreferred(&EC, 0.0);
716 QCBOREncode_AddDoubleNoPreferred(&EC, NAN);
717 QCBOREncode_AddDoubleNoPreferred(&EC, INFINITY);
718
719 QCBOREncode_AddFloat(&EC, 0.0);
720 QCBOREncode_AddFloat(&EC, 3.14f);
721 QCBOREncode_AddFloatNoPreferred(&EC, 0.0f);
722 QCBOREncode_AddFloatNoPreferred(&EC, NAN);
723 QCBOREncode_AddFloatNoPreferred(&EC, INFINITY);
724
725 QCBOREncode_OpenMap(&EC);
726
727 QCBOREncode_AddDoubleToMapN(&EC, 100, 0.0);
728 QCBOREncode_AddDoubleToMapN(&EC, 101, 3.1415926);
729 QCBOREncode_AddDoubleToMap(&EC, "euler", 2.71828182845904523536);
730 QCBOREncode_AddDoubleNoPreferredToMapN(&EC, 105, 0.0);
731
732 QCBOREncode_AddFloatToMapN(&EC, 102, 0.0f);
733 QCBOREncode_AddFloatToMapN(&EC, 103, 3.1415926f);
734 QCBOREncode_AddFloatToMap(&EC, "euler2", 2.71828182845904523536f);
735 QCBOREncode_AddFloatNoPreferredToMapN(&EC, 106, 0.0f);
736
737 QCBOREncode_CloseMap(&EC);
738 QCBOREncode_CloseArray(&EC);
739
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700740 uErr = QCBOREncode_Finish(&EC, &Encoded);
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700741 if(uErr) {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700742 return -1;
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700743 }
744
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700745 if(UsefulBuf_Compare(Encoded, ExpectedFloats)) {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700746 return -3;
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700747 }
748
749 return 0;
750}
751
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200752#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700753
754
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700755/* Public function. See float_tests.h */
756int32_t
757GeneralFloatDecodeTests(void)
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700758{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700759 /* See FloatNumberTests() for tests that really cover lots of float values */
760
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700761 QCBORItem Item;
762 QCBORError uErr;
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700763 QCBORDecodeContext DC;
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700764
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700765 UsefulBufC TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
766 QCBORDecode_Init(&DC, TestData, 0);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700767
768 QCBORDecode_GetNext(&DC, &Item);
769 if(Item.uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700770 return MakeTestResultCode(0, 1, 0);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700771 }
772
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700773 /* 0.0 half-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700774 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200775 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
776#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
777 || Item.uDataType != QCBOR_TYPE_DOUBLE
778 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700779#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
780 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200781#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
782 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700783 return MakeTestResultCode(0, 2, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700784 }
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700785
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700786 /* 3.14 double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700787 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200788 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
789#ifndef USEFULBUF_DISABLE_ALL_FLOAT
790 || Item.uDataType != QCBOR_TYPE_DOUBLE
791 || Item.val.dfnum != 3.14
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700792#else /* USEFULBUF_DISABLE_ALL_FLOAT */
793 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200794#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
795 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700796 return MakeTestResultCode(0, 3, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700797 }
798
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700799 /* 0.0 double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700800 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200801 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
802#ifndef USEFULBUF_DISABLE_ALL_FLOAT
803 || Item.uDataType != QCBOR_TYPE_DOUBLE
804 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700805#else /* USEFULBUF_DISABLE_ALL_FLOAT */
806 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200807#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
808 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700809 return MakeTestResultCode(0, 4, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700810 }
811
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700812 /* NaN double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700813 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200814 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
815#ifndef USEFULBUF_DISABLE_ALL_FLOAT
816 || Item.uDataType != QCBOR_TYPE_DOUBLE
817 || !isnan(Item.val.dfnum)
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700818#else /* USEFULBUF_DISABLE_ALL_FLOAT */
819 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200820#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
821 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700822 return MakeTestResultCode(0, 5, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700823 }
824
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700825 /* Infinity double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700826 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200827 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
828#ifndef USEFULBUF_DISABLE_ALL_FLOAT
829 || Item.uDataType != QCBOR_TYPE_DOUBLE
830 || Item.val.dfnum != INFINITY
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700831#else /* USEFULBUF_DISABLE_ALL_FLOAT */
832 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200833#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
834 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700835 return MakeTestResultCode(0, 6, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700836 }
837
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700838 /* 0.0 half-precision (again) */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700839 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200840 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
841#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
842 || Item.uDataType != QCBOR_TYPE_DOUBLE
843 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700844#else /* USEFULBUF_DISABLE_ALL_FLOAT */
845 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200846#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
847 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700848 return MakeTestResultCode(0, 7, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700849 }
850
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700851 /* 3.140000104904175 single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700852 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200853 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
854#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700855#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200856 || Item.uDataType != QCBOR_TYPE_DOUBLE
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700857 || 3.1400001049041748 != Item.val.dfnum
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700858#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200859 || Item.uDataType != QCBOR_TYPE_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700860 || 3.140000f != Item.val.fnum
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700861#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
862#else /* USEFULBUF_DISABLE_ALL_FLOAT */
863 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200864#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
865 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700866 return MakeTestResultCode(0, 8, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700867 }
868
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700869 /* 0.0 single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700870 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200871 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
872#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700873#ifndef QCBOR_DISABLE_FLOAT_HW_USE
874 || Item.uDataType != QCBOR_TYPE_DOUBLE
875 || Item.val.dfnum != 0.0
876#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200877 || Item.uDataType != QCBOR_TYPE_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700878 || Item.val.fnum != 0.0f
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700879#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
880#else /* USEFULBUF_DISABLE_ALL_FLOAT */
881 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200882#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
883 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700884 return MakeTestResultCode(0, 9, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700885 }
886
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700887 /* NaN single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700888 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200889 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
890#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700891#ifndef QCBOR_DISABLE_FLOAT_HW_USE
892 || Item.uDataType != QCBOR_TYPE_DOUBLE
893 || !isnan(Item.val.dfnum)
894#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200895 || Item.uDataType != QCBOR_TYPE_FLOAT
896 || !isnan(Item.val.fnum)
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700897#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
898#else /* USEFULBUF_DISABLE_ALL_FLOAT */
899 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200900#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
901 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700902 return MakeTestResultCode(0, 10, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700903 }
904
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700905 /* Infinity single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700906 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200907 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
908#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700909#ifndef QCBOR_DISABLE_FLOAT_HW_USE
910 || Item.uDataType != QCBOR_TYPE_DOUBLE
911 || Item.val.dfnum != INFINITY
912#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200913 || Item.uDataType != QCBOR_TYPE_FLOAT
914 || Item.val.fnum != INFINITY
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700915#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
916#else /* USEFULBUF_DISABLE_ALL_FLOAT */
917 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200918#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
919 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700920 return MakeTestResultCode(0, 11, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700921 }
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700922 /* Sufficent test coverage. Don't need to decode the rest. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700923
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200924
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200925#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700926 /* Now tests for spiffy decode main function */
927 TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700928 double d;
929 QCBORDecode_Init(&DC, TestData, 0);
Laurence Lundblade6545d1b2020-10-14 11:13:13 -0700930 QCBORDecode_EnterArray(&DC, NULL);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700931
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700932 /* 0.0 half-precision */
933 QCBORDecode_GetDouble(&DC, &d);
934 uErr = QCBORDecode_GetAndResetError(&DC);
935 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700936#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700937 || d != 0.0
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700938#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700939 ) {
940 return MakeTestResultCode(1, 1, uErr);
941 }
942
943 /* 3.14 double-precision */
944 QCBORDecode_GetDouble(&DC, &d);
945 uErr = QCBORDecode_GetAndResetError(&DC);
946 if(uErr != QCBOR_SUCCESS || d != 3.14) {
947 return MakeTestResultCode(1, 2, uErr);
948 }
949
950 /* 0.0 double-precision */
951 QCBORDecode_GetDouble(&DC, &d);
952 uErr = QCBORDecode_GetAndResetError(&DC);
953 if(uErr != QCBOR_SUCCESS || d != 0.0) {
954 return MakeTestResultCode(1, 3, uErr);
955 }
956
957 /* NaN double-precision */
958 QCBORDecode_GetDouble(&DC, &d);
959 uErr = QCBORDecode_GetAndResetError(&DC);
960 if(uErr != QCBOR_SUCCESS || !isnan(d)) {
961 return MakeTestResultCode(1, 4, uErr);
962 }
963
964 /* Infinity double-precision */
965 QCBORDecode_GetDouble(&DC, &d);
966 uErr = QCBORDecode_GetAndResetError(&DC);
967 if(uErr != QCBOR_SUCCESS || d != INFINITY) {
968 return MakeTestResultCode(1, 5, uErr);
969 }
970
971 /* 0.0 half-precision */
972 QCBORDecode_GetDouble(&DC, &d);
973 uErr = QCBORDecode_GetAndResetError(&DC);
974 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
975#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
976 || d != 0.0
977#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
978 ) {
979 return MakeTestResultCode(1, 6, uErr);
980 }
981
982 /* 3.140000104904175 single-precision */
983 QCBORDecode_GetDouble(&DC, &d);
984 uErr = QCBORDecode_GetAndResetError(&DC);
985 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
986#ifndef QCBOR_DISABLE_FLOAT_HW_USE
987 || d != 3.140000104904175
988#endif
989 ) {
990 return MakeTestResultCode(1, 7, uErr);
991 }
992
993 /* 0.0 single-precision */
994 QCBORDecode_GetDouble(&DC, &d);
995 uErr = QCBORDecode_GetAndResetError(&DC);
996 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
997#ifndef QCBOR_DISABLE_FLOAT_HW_USE
998 || d != 0.0
999#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1000 ) {
1001 return MakeTestResultCode(1, 8, uErr);
1002 }
1003
1004 /* NaN single-precision */
1005 QCBORDecode_GetDouble(&DC, &d);
1006 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1007#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1008 || !isnan(d)
1009#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1010 ) {
1011 return MakeTestResultCode(1, 9, uErr);
1012 }
1013
1014 /* Infinity single-precision */
1015 QCBORDecode_GetDouble(&DC, &d);
1016 uErr = QCBORDecode_GetAndResetError(&DC);
1017 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1018#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1019 || d != INFINITY
1020#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1021 ) {
1022 return MakeTestResultCode(1, 10, uErr);
1023 }
1024
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001025#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001026
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001027 return 0;
1028}
1029
1030
Laurence Lundbladed711fb22018-09-26 14:35:22 -07001031
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001032#ifdef NAN_EXPERIMENT
1033/*
1034 Code for checking what the double to float cast does with
1035 NaNs. Not run as part of tests. Keep it around to
1036 be able to check various platforms and CPUs.
1037 */
1038
1039#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
1040#define DOUBLE_NUM_EXPONENT_BITS (11)
1041#define DOUBLE_NUM_SIGN_BITS (1)
1042
1043#define DOUBLE_SIGNIFICAND_SHIFT (0)
1044#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS)
1045#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
1046
1047#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits
1048#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
1049#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
1050#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
1051
1052
1053static int NaNExperiments() {
1054 double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
1055 double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
1056 double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001057
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001058 float f1 = (float)dqNaN;
1059 float f2 = (float)dsNaN;
1060 float f3 = (float)dqNaNPayload;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001061
1062
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001063 uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
1064 uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
1065 uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001066
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001067 // Result of this on x86 is that every NaN is a qNaN. The intel
1068 // CVTSD2SS instruction ignores the NaN payload and even converts
1069 // a sNaN to a qNaN.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001070
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001071 return 0;
1072}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001073#endif /* NAN_EXPERIMENT */