blob: a46f090128ef7ea17b3342efac8e084e8e5cfedc [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 *
9 * See BSD-3-Clause license in README.md
10 *
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 Lundbladebf8e1cf2024-01-17 11:58:24 -070044struct FloatTestCase {
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070045 double dNumber;
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -070046 float fNumber;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070047 UsefulBufC Preferred;
48 UsefulBufC NotPreferred;
49 UsefulBufC CDE;
50 UsefulBufC DCBOR;
51};
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -070052
Laurence Lundbladee026f4f2024-01-18 13:48:34 -070053/* Boundaries for destination conversions:
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070054 *
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 *
Laurence Lundbladee026f4f2024-01-18 13:48:34 -070065 * Boundaries for origin conversions:
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070066 * 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 Lundbladebf8e1cf2024-01-17 11:58:24 -070070 *
Laurence Lundbladee026f4f2024-01-18 13:48:34 -070071 * Boundaries for double conversion to 64-bit integer:
72 * exponent 51, 52 significand bits set 4503599627370495
73 * exponent 52, 52 significand bits set 9007199254740991
74 * exponent 53, 52 bits set in significand 18014398509481982
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070075 */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070076
77/* Always four lines per test case so shell scripts can process into
Laurence Lundbladee026f4f2024-01-18 13:48:34 -070078 * other formats. CDE and DCBOR standards are not complete yet,
79 * encodings are what is expected. C string literals are used because they
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070080 * are the shortest notation. They are used __with a length__ . Null
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -070081 * termination doesn't work because there are zero bytes.
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070082 */
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -070083static const struct FloatTestCase FloatTestCases[] = {
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070084 /* Zero */
85 {0.0, 0.0f,
86 {"\xF9\x00\x00", 3}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundblade240ca822024-01-16 11:11:00 -070087 {"\xF9\x00\x00", 3}, {"\x00", 1}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070088
89 /* Negative Zero */
90 {-0.0, -0.0f,
91 {"\xF9\x80\x00", 3}, {"\xFB\x80\x00\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundblade240ca822024-01-16 11:11:00 -070092 {"\xF9\x80\x00", 3}, {"\x00", 1}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070093
94 /* NaN */
95 {NAN, NAN,
96 {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9},
97 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
98
99 /* Infinity */
100 {INFINITY, INFINITY,
101 {"\xF9\x7C\x00", 3}, {"\xFB\x7F\xF0\x00\x00\x00\x00\x00\x00", 9},
102 {"\xF9\x7C\x00", 3}, {"\xF9\x7C\x00", 3}},
103
104 /* Negative Infinity */
105 {-INFINITY, -INFINITY,
106 {"\xF9\xFC\x00", 3}, {"\xFB\xFF\xF0\x00\x00\x00\x00\x00\x00", 9},
107 {"\xF9\xFC\x00", 3}, {"\xF9\xFC\x00", 3}},
108
109 /* 1.0 */
110 {1.0, 1.0f,
111 {"\xF9\x3C\x00", 3}, {"\xFB\x3F\xF0\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundblade240ca822024-01-16 11:11:00 -0700112 {"\xF9\x3C\x00", 3}, {"\x01", 1}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700113
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700114 /* -2.0 -- a negative */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700115 {-2.0, -2.0f,
116 {"\xF9\xC0\x00", 3}, {"\xFB\xC0\x00\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundblade240ca822024-01-16 11:11:00 -0700117 {"\xF9\xC0\x00", 3}, {"\x21", 1}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700118
119 /* 1/3 */
120 {0.333251953125, 0.333251953125f,
121 {"\xF9\x35\x55", 3}, {"\xFB\x3F\xD5\x54\x00\x00\x00\x00\x00", 9},
122 {"\xF9\x35\x55", 3}, {"\xF9\x35\x55", 3}},
123
124 /* 5.9604644775390625E-8 -- smallest half-precision subnormal */
125 {5.9604644775390625E-8, 0.0f,
126 {"\xF9\x00\x01", 3}, {"\xFB\x3E\x70\x00\x00\x00\x00\x00\x00", 9},
127 {"\xF9\x00\x01", 3}, {"\xF9\x00\x01", 3}},
128
129 /* 3.0517578125E-5 -- a half-precision subnormal */
130 {3.0517578125E-5, 0.0f,
131 {"\xF9\x02\x00", 3}, {"\xFB\x3F\x00\x00\x00\x00\x00\x00\x00", 9},
132 {"\xF9\x02\x00", 3}, {"\xF9\x02\x00", 3}},
133
134 /* 6.097555160522461E-5 -- largest half-precision subnormal */
135 {6.097555160522461E-5, 0.0f,
136 {"\xF9\x03\xFF", 3}, {"\xFB\x3F\x0F\xF8\x00\x00\x00\x00\x00", 9},
Laurence Lundblade240ca822024-01-16 11:11:00 -0700137 {"\xF9\x03\xFF", 3}, {"\xF9\x03\xFF", 3}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700138
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700139 /* 6.1035156249999993E-5 -- slightly smaller than smallest half-precision normal */
140 {6.1035156249999993E-5, 0.0f,
141 {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
142 {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
143
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700144 /* 6.103515625E-5 -- smallest half-precision normal */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700145 {6.103515625E-5, 0.0f,
146 {"\xF9\04\00", 3}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x00", 9},
147 {"\xF9\04\00", 3}, {"\xF9\04\00", 3}},
148
149 /* 6.1035156250000014E-5 -- slightly larger than smallest half-precision normal */
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700150 {6.1035156250000014E-5, 0.0f,
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700151 {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9},
152 {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}},
153
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700154 /* 65504.0 -- largest half-precision */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700155 {65504.0, 0.0f,
156 {"\xF9\x7B\xFF", 3}, {"\xFB\x40\xEF\xFC\x00\x00\x00\x00\x00", 9},
Laurence Lundblade240ca822024-01-16 11:11:00 -0700157 {"\xF9\x7B\xFF", 3}, {"\x19\xFF\xE0", 3}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700158
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700159 /* 65504.1 -- exponent too large and too much precision to convert to half */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700160 {65504.1, 0.0f,
161 {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9},
162 {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}},
163
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700164 /* 65536.0 -- exponent too large for half but not too much precision for single */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700165 {65536.0, 65536.0f,
166 {"\xFA\x47\x80\x00\x00", 5}, {"\xFB\x40\xF0\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundblade240ca822024-01-16 11:11:00 -0700167 {"\xFA\x47\x80\x00\x00", 5}, {"\x1A\x00\x01\x00\x00", 5}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700168
169 /* 1.401298464324817e-45 -- smallest single subnormal */
170 {1.401298464324817e-45, 1.40129846E-45f,
171 {"\xFA\x00\x00\x00\x01", 5}, {"\xFB\x36\xA0\x00\x00\x00\x00\x00\x00", 9},
172 {"\xFA\x00\x00\x00\x01", 5}, {"\xFA\x00\x00\x00\x01", 5}},
173
Laurence Lundblade240ca822024-01-16 11:11:00 -0700174 /* 5.8774717541114375E-39 -- slightly smaller than the smallest single normal */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700175 {5.8774717541114375E-39, 5.87747175E-39f,
176 {"\xFA\x00\x40\x00\x00", 5}, {"\xFB\x38\x00\x00\x00\x00\x00\x00\x00", 9},
177 {"\xFA\x00\x40\x00\x00", 5}, {"\xFA\x00\x40\x00\x00", 5}},
178
179 /* 1.1754942106924411e-38 -- largest single subnormal */
180 {1.1754942106924411E-38, 1.17549421E-38f,
181 {"\xFA\x00\x7f\xff\xff", 5}, {"\xFB\x38\x0f\xff\xff\xC0\x00\x00\x00", 9},
182 {"\xFA\x00\x7f\xff\xff", 5}, {"\xFA\x00\x7f\xff\xff", 5} },
183
184 /* 1.1754943508222874E-38 -- slightly bigger than smallest single normal */
185 {1.1754943508222874E-38, 0.0f,
186 {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9},
187 {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}},
188
189 /* 1.1754943508222875e-38 -- smallest single normal */
190 {1.1754943508222875e-38, 1.17549435E-38f,
191 {"\xFA\x00\x80\x00\x00", 5}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x00", 9},
192 {"\xFA\x00\x80\x00\x00", 5}, {"\xFA\x00\x80\x00\x00", 5}},
193
194 /* 1.1754943508222875e-38 -- slightly bigger than smallest single normal */
195 {1.1754943508222878e-38, 0.0f,
196 {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9},
197 {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}},
198
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700199 /* 8388607 -- exponent 22 to test single exponent boundary */
200 {8388607, 8388607.0f,
201 {"\xFA\x4A\xFF\xFF\xFE", 5}, {"\xFB\x41\x5F\xFF\xFF\xC0\x00\x00\x00", 9},
202 {"\xFA\x4A\xFF\xFF\xFE", 5}, {"\x1A\x00\x7F\xFF\xFF", 5}},
203
204 /* 16777215 -- exponent 23 to test single exponent boundary */
205 {16777215, 16777215.0f,
206 {"\xFA\x4B\x7F\xFF\xFF", 5}, {"\xFB\x41\x6F\xFF\xFF\xE0\x00\x00\x00", 9},
207 {"\xFA\x4B\x7F\xFF\xFF", 5}, {"\x1A\x00\xFF\xFF\xFF", 5}},
208
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700209 /* 16777216 -- converts to single without loss */
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700210 {16777216, 16777216.0f,
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700211 {"\xFA\x4B\x80\x00\x00", 5}, {"\xFB\x41\x70\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundblade240ca822024-01-16 11:11:00 -0700212 {"\xFA\x4B\x80\x00\x00", 5}, {"\x1A\x01\x00\x00\x00", 5}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700213
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700214 /* 16777217 -- one more than above and fails conversion to single because of precision */
215 {16777217, 0.0f,
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700216 {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9},
Laurence Lundblade240ca822024-01-16 11:11:00 -0700217 {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\x1A\x01\x00\x00\x01", 5}},
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700218
219 /* 33554430 -- exponent 24 to test single exponent boundary */
220 {33554430, 33554430.0f,
221 {"\xFA\x4B\xFF\xFF\xFF", 5}, {"\xFB\x41\x7F\xFF\xFF\xE0\x00\x00\x00", 9},
222 {"\xFA\x4B\xFF\xFF\xFF", 5}, {"\x1A\x01\xFF\xFF\xFE", 5}},
Laurence Lundblade240ca822024-01-16 11:11:00 -0700223
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700224 /* 4294967295 -- 2^^32 - 1 UINT32_MAX */
Laurence Lundblade240ca822024-01-16 11:11:00 -0700225 {4294967295, 0,
226 {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9},
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700227 {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\x1A\xFF\xFF\xFF\xFF", 5}},
Laurence Lundblade240ca822024-01-16 11:11:00 -0700228
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700229 /* 4294967296 -- 2^^32, UINT32_MAX + 1 */
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700230 {4294967296, 4294967296.0f,
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700231 {"\xFA\x4F\x80\x00\x00", 5}, {"\xFB\x41\xF0\x00\x00\x00\x00\x00\x00", 9},
232 {"\xFA\x4F\x80\x00\x00", 5}, {"\x1B\x00\x00\x00\x01\x00\x00\x00\x00", 9}},
233
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700234 /* 2251799813685248 -- exponent 51, 0 significand bits set, to test double exponent boundary */
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700235 {2251799813685248, 0,
236 {"\xFA\x59\x00\x00\x00", 5}, {"\xFB\x43\x20\x00\x00\x00\x00\x00\x00", 9},
237 {"\xFA\x59\x00\x00\x00", 5}, {"\x1B\x00\x08\x00\x00\x00\x00\x00\x00", 9}},
238
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700239 /* 4503599627370495 -- exponent 51, 52 significand bits set to test double exponent boundary*/
Laurence Lundblade240ca822024-01-16 11:11:00 -0700240 {4503599627370495, 0,
241 {"\xFB\x43\x2F\xFF\xFF\xFF\xFF\xFF\xFE", 9}, {"\xFB\x43\x2F\xFF\xFF\xFF\xFF\xFF\xFE", 9},
242 {"\xFB\x43\x2F\xFF\xFF\xFF\xFF\xFF\xFE", 9}, {"\x1B\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
243
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700244 /* 9007199254740991 -- exponent 52, 52 significand bits set to test double exponent boundary */
Laurence Lundblade240ca822024-01-16 11:11:00 -0700245 {9007199254740991, 0,
246 {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
247 {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\x00\x1F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
248
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700249 /* 18014398509481982 -- exponent 53, 52 bits set in significand (double lacks precision to represent 18014398509481983) */
Laurence Lundblade240ca822024-01-16 11:11:00 -0700250 {18014398509481982, 0,
251 {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
252 {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFE", 9}},
253
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700254 /* 18014398509481984 -- next largest possible double above 18014398509481982 */
Laurence Lundblade240ca822024-01-16 11:11:00 -0700255 {18014398509481984, 0,
256 {"\xFA\x5A\x80\x00\x00", 5}, {"\xFB\x43\x50\x00\x00\x00\x00\x00\x00", 9},
257 {"\xFA\x5A\x80\x00\x00", 5}, {"\x1B\x00\x40\x00\x00\x00\x00\x00\x00", 9}},
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700258
259 /* 18446742974197924000.0.0 -- largest single that can convert to uint64 */
260 {18446742974197924000.0, 18446742974197924000.0f,
261 {"\xFA\x5F\x7F\xFF\xFF", 5}, {"\xFB\x43\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
262 {"\xFA\x5F\x7F\xFF\xFF", 5}, {"\x1B\xFF\xFF\xFF\x00\x00\x00\x00\x00", 9}},
Laurence Lundblade240ca822024-01-16 11:11:00 -0700263
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700264 /* 18446744073709550000.0 -- largest double that can convert to uint64, almost UINT64_MAX (18446744073709551615) */
265 {18446744073709550000.0, 0,
266 {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
267 {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00", 9}},
268
269 /* 18446744073709552000.0 -- just too large to convert to uint64, but converts to a single, just over UINT64_MAX */
270 {18446744073709552000.0, 18446744073709552000.0f,
271 {"\xFA\x5F\x80\x00\x00", 5}, {"\xFB\x43\xF0\x00\x00\x00\x00\x00\x00", 9},
272 {"\xFA\x5F\x80\x00\x00", 5}, {"\xFA\x5F\x80\x00\x00", 5}},
273
274 /* -4294967295 -- negative UINT32_MAX */
275 {-4294967295.0, 0,
Laurence Lundblade240ca822024-01-16 11:11:00 -0700276 {"\xFB\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\xFB\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", 9},
277 {"\xFB\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\x3A\xFF\xFF\xFF\xFE", 5}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700278
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700279 /* -9223372036854774784.0 -- most negative double that converts to int64 */
280 {-9223372036854774784.0, 0,
281 {"\xFB\xC3\xDF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\xC3\xDF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
282 {"\xFB\xC3\xDF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x3B\x7F\xFF\xFF\xFF\xFF\xFF\xFB\xFF", 9}},
283
284 /* -18446742974197924000.0.0 -- large negative that converts to float, but too large for int64 */
285 {-18446742974197924000.0, -18446742974197924000.0f,
286 {"\xFA\xDF\x7F\xFF\xFF", 5}, {"\xFB\xC3\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
287 {"\xFA\xDF\x7F\xFF\xFF", 5}, {"\xFA\xDF\x7F\xFF\xFF", 5}},
288
289 /* 3.4028234663852886E+38 -- largest possible single */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700290 {3.4028234663852886E+38, 3.40282347E+38f,
Laurence Lundbladee026f4f2024-01-18 13:48:34 -0700291 {"\xFA\x7F\x7F\xFF\xFF", 5}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
292 {"\xFA\x7F\x7F\xFF\xFF", 5}, {"\xFA\x7F\x7F\xFF\xFF", 5}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700293
294 /* 3.402823466385289E+38 -- slightly larger than largest possible single */
295 {3.402823466385289E+38, 0.0f,
296 {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9},
297 {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}},
298
299 /* 3.402823669209385e+38 -- exponent larger by one than largest possible single */
300 {3.402823669209385e+38, 0.0f,
301 {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9},
302 {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}},
303
304 /* 5.0e-324 -- smallest double subnormal normal */
305 {5.0e-324, 0.0f,
306 {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9},
307 {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}},
308
309 /* 2.2250738585072009E−308 -- largest double subnormal */
310 {2.2250738585072009e-308, 0.0f,
311 {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
312 {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
313
314 /* 2.2250738585072014e-308 -- smallest double normal */
315 {2.2250738585072014e-308, 0.0f,
316 {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9},
317 {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}},
318
319 /* 1.7976931348623157E308 -- largest double normal */
320 {1.7976931348623157e308, 0.0f,
321 {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
322 {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
323
324 /* List terminator */
325 {0.0, 0.0f, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700326};
327
328
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700329/* Can't use types double and float here because there's no way in C to
330 * construct arbitrary payloads for those types.
331 */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700332struct NaNTestCase {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700333 uint64_t uDouble; /* Converted to double in test */
334 uint32_t uSingle; /* Converted to single in test */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700335 UsefulBufC Preferred;
336 UsefulBufC NotPreferred;
337 UsefulBufC CDE;
338 UsefulBufC DCBOR;
339};
340
341/* Always four lines per test case so shell scripts can process into
342 * other formats. CDE and DCBOR standards are not complete yet,
343 * encodings are a guess. C string literals are used because they
344 * are the shortest notation. They are used __with a length__ . Null
345 * termination doesn't work because there are zero bytes.
346 */
347static const struct NaNTestCase NaNTestCases[] = {
348
349 /* Payload with most significant bit set, a qNaN by most implementations */
350 {0x7ff8000000000000, 0x00000000,
351 {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9},
352 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
353
354 /* Payload with single rightmost set */
355 {0x7ff8000000000001, 0x00000000,
356 {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x01", 9},
357 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
358
359 /* Payload with 10 leftmost bits set -- converts to half */
360 {0x7ffffc0000000000, 0x00000000,
361 {"\xF9\x7F\xFF", 3}, {"\xFB\x7F\xFF\xFC\x00\x00\x00\x00\x00", 9},
362 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
363
364 /* Payload with 10 rightmost bits set -- cannot convert to half */
365 {0x7ff80000000003ff, 0x00000000,
366 {"\xFB\x7F\xF8\x00\x00\x00\x00\x03\xFF", 9}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x03\xFF", 9},
367 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
368
369 /* Payload with 23 leftmost bits set -- converts to a single */
370 {0x7ffFFFFFE0000000, 0x7fffffff,
371 {"\xFA\x7F\xFF\xFF\xFF", 5}, {"\xFB\x7F\xFF\xFF\xFF\xE0\x00\x00\x00", 9},
372 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
373
374 /* Payload with 24 leftmost bits set -- fails to convert to a single */
375 {0x7ffFFFFFF0000000, 0x00000000,
376 {"\xFB\x7F\xFF\xFF\xFF\xF0\x00\x00\x00", 9}, {"\xFB\x7F\xFF\xFF\xFF\xF0\x00\x00\x00", 9},
377 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
378
379 /* Payload with all bits set */
380 {0x7fffffffffffffff, 0x00000000,
381 {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
Laurence Lundblade240ca822024-01-16 11:11:00 -0700382 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700383
384 /* List terminator */
385 {0, 0, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} }
386};
387
388
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700389/* Public function. See float_tests.h
390 *
391 * This is the main test of floating-point encoding / decoding. It is
392 * data-driven by the above tables. It works better than tests below that
393 * it mostly replaces because it tests one number at a time, rather than
394 * putting them all in a map. It is much easier to debug test failures
395 * and to add new tests. */
396int32_t
397FloatValuesTests(void)
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700398{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700399 unsigned int uTestIndex;
Laurence Lundbladee75f5962024-02-15 17:51:32 -0800400 const struct FloatTestCase *pTestCase;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700401 const struct NaNTestCase *pNaNTestCase;
402 MakeUsefulBufOnStack( TestOutBuffer, 20);
403 UsefulBufC TestOutput;
404 QCBOREncodeContext EnCtx;
405 QCBORError uErr;
406 QCBORDecodeContext DCtx;
407 QCBORItem Item;
408 uint64_t uDecoded;
409#ifdef QCBOR_DISABLE_FLOAT_HW_USE
410 uint32_t uDecoded2;
411#endif
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700412
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700413 /* Test a variety of doubles */
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700414 for(uTestIndex = 0; FloatTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
415 pTestCase = &FloatTestCases[uTestIndex];
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700416
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700417 /* Number Encode of Preferred */
418 QCBOREncode_Init(&EnCtx, TestOutBuffer);
419 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
420 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800421
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700422 if(uErr != QCBOR_SUCCESS) {
423 return MakeTestResultCode(uTestIndex, 1, uErr);;
424 }
425 if(UsefulBuf_Compare(TestOutput, pTestCase->Preferred)) {
426 return MakeTestResultCode(uTestIndex, 1, 200);
427 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700428
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700429 /* Number Encode of Not Preferred */
430 QCBOREncode_Init(&EnCtx, TestOutBuffer);
431 QCBOREncode_AddDoubleNoPreferred(&EnCtx, pTestCase->dNumber);
432 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
Laurence Lundblade68a13352018-09-23 02:19:54 -0700433
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700434 if(uErr != QCBOR_SUCCESS) {
435 return MakeTestResultCode(uTestIndex, 2, uErr);;
436 }
437 if(UsefulBuf_Compare(TestOutput, pTestCase->NotPreferred)) {
438 return MakeTestResultCode(uTestIndex, 2, 200);
439 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800440
Laurence Lundblade240ca822024-01-16 11:11:00 -0700441 /* Number Encode of CDE */
442 QCBOREncode_Init(&EnCtx, TestOutBuffer);
443 QCBOREncode_SerializationCDE(&EnCtx);
444 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
445 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
446
447 if(uErr != QCBOR_SUCCESS) {
448 return MakeTestResultCode(uTestIndex, 20, uErr);;
449 }
450 if(UsefulBuf_Compare(TestOutput, pTestCase->CDE)) {
451 return MakeTestResultCode(uTestIndex, 21, 200);
452 }
453
454 /* Number Encode of dCBOR */
455 QCBOREncode_Init(&EnCtx, TestOutBuffer);
456 QCBOREncode_SerializationdCBOR(&EnCtx);
457 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
458 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
459
460 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700461 return MakeTestResultCode(uTestIndex, 22, uErr);;
Laurence Lundblade240ca822024-01-16 11:11:00 -0700462 }
463 if(UsefulBuf_Compare(TestOutput, pTestCase->DCBOR)) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700464 return MakeTestResultCode(uTestIndex, 23, 200);
465 }
466
467 if(pTestCase->fNumber != 0) {
468 QCBOREncode_Init(&EnCtx, TestOutBuffer);
469 QCBOREncode_SerializationdCBOR(&EnCtx);
470 QCBOREncode_AddFloat(&EnCtx, pTestCase->fNumber);
471 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
472
473 if(uErr != QCBOR_SUCCESS) {
474 return MakeTestResultCode(uTestIndex, 24, uErr);;
475 }
476 if(UsefulBuf_Compare(TestOutput, pTestCase->DCBOR)) {
477 return MakeTestResultCode(uTestIndex, 25, 200);
478 }
Laurence Lundblade240ca822024-01-16 11:11:00 -0700479 }
480
481
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700482 /* Number Decode of Preferred */
483 QCBORDecode_Init(&DCtx, pTestCase->Preferred, 0);
484 uErr = QCBORDecode_GetNext(&DCtx, &Item);
485 if(uErr != QCBOR_SUCCESS) {
486 return MakeTestResultCode(uTestIndex, 3, uErr);;
487 }
488#ifndef QCBOR_DISABLE_FLOAT_HW_USE
489 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
490 return MakeTestResultCode(uTestIndex, 4, 0);
491 }
492 if(isnan(pTestCase->dNumber)) {
493 if(!isnan(Item.val.dfnum)) {
494 return MakeTestResultCode(uTestIndex, 5, 0);
495 }
496 } else {
497 if(Item.val.dfnum != pTestCase->dNumber) {
498 return MakeTestResultCode(uTestIndex, 6, 0);
499 }
500 }
501#else /* QCBOR_DISABLE_FLOAT_HW_USE */
502 /* When QCBOR_DISABLE_FLOAT_HW_USE is set, single-precision is not
503 * converted to double when decoding, so test differently. len == 5
504 * indicates single-precision in the encoded CBOR. */
505 if(pTestCase->Preferred.len == 5) {
506 if(Item.uDataType != QCBOR_TYPE_FLOAT) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700507 return MakeTestResultCode(uTestIndex, 41, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700508 }
509 if(isnan(pTestCase->dNumber)) {
510 if(!isnan(Item.val.fnum)) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700511 return MakeTestResultCode(uTestIndex, 51, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700512 }
513 } else {
514 if(Item.val.fnum != pTestCase->fNumber) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700515 return MakeTestResultCode(uTestIndex, 61, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700516 }
517 }
518 } else {
519 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700520 return MakeTestResultCode(uTestIndex, 42, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700521 }
522 if(isnan(pTestCase->dNumber)) {
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700523 if(!isnan(Item.val.dfnum)) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700524 return MakeTestResultCode(uTestIndex, 52, 0);
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700525 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700526 } else {
527 if(Item.val.dfnum != pTestCase->dNumber) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700528 return MakeTestResultCode(uTestIndex, 62, 0);
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700529 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700530 }
531 }
532#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700533
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700534 /* Number Decode of Not Preferred */
535 QCBORDecode_Init(&DCtx, pTestCase->NotPreferred, 0);
536 uErr = QCBORDecode_GetNext(&DCtx, &Item);
537 if(uErr != QCBOR_SUCCESS) {
538 return MakeTestResultCode(uTestIndex, 7, uErr);;
539 }
540 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
541 return MakeTestResultCode(uTestIndex, 8, 0);
542 }
543 if(isnan(pTestCase->dNumber)) {
544 if(!isnan(Item.val.dfnum)) {
545 return MakeTestResultCode(uTestIndex, 9, 0);
546 }
547 } else {
548 if(Item.val.dfnum != pTestCase->dNumber) {
549 return MakeTestResultCode(uTestIndex, 10, 0);
550 }
551 }
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700552
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700553 }
554
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700555 /* Test a variety of NaNs with payloads */
556 for(uTestIndex = 0; NaNTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
557 pNaNTestCase = &NaNTestCases[uTestIndex];
558
559
560 if(uTestIndex == 4) {
561 uErr = 99; /* For setting break points for particular tests */
562 }
563
564 /* NaN Encode of Preferred */
565 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade8e5f42d2024-02-11 14:25:32 -0800566 QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700567 QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
568 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
569 if(uErr != QCBOR_SUCCESS) {
570 return MakeTestResultCode(uTestIndex+100, 10, uErr);;
571 }
572 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) {
573 return MakeTestResultCode(uTestIndex+100, 10, 200);
574 }
575
576#ifdef QCBOR_COMPARE_TO_HW_NAN_CONVERSION
577 {
578 /* This test is off by default. It's purpose is to check
579 * QCBOR's mask-n-shift implementation against the HW/CPU
580 * instructions that do conversion between double and single.
581 * It is off because it is only used on occasion to verify
582 * QCBOR and because it is suspected that some HW/CPU does
583 * implement this correctly. NaN payloads are an obscure
584 * feature. */
585 float f;
586 double d, d2;
587
588 d = UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uNumber);
589
590 /* Cast the double to a single and then back to a double and
591 * see if they are equal. If so, then the NaN payload doesn't
592 * have any bits that are lost when converting to single and
593 * it can be safely converted.
594 *
595 * This test can't be done for half-precision because it is
596 * not widely supported.
597 */
598 f = (float)d;
599 d2 = (double)f;
600
601 /* The length of encoded doubles is 9, singles 5 and halves
602 * 3. If there are NaN payload bits that can't be converted,
603 * then the length must be 9.
604 */
605 if((uint64_t)d != (uint64_t)d2 && pNaNTestCase->Preferred.len != 9) {
606 /* QCBOR conversion not the same as HW conversion */
607 return MakeTestResultCode(uTestIndex, 9, 200);
608 }
609 }
610#endif /* QCBOR_COMPARE_TO_HW_NAN_CONVERSION */
611
612
613 /* NaN Encode of Not Preferred */
614 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade8e5f42d2024-02-11 14:25:32 -0800615 QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700616 QCBOREncode_AddDoubleNoPreferred(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
617 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
618 if(uErr != QCBOR_SUCCESS) {
619 return MakeTestResultCode(uTestIndex+100, 11, uErr);;
620 }
621 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
622 return MakeTestResultCode(uTestIndex+100, 11, 200);
623 }
624
Laurence Lundblade240ca822024-01-16 11:11:00 -0700625 /* NaN Decode of Not Preferred */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700626 QCBORDecode_Init(&DCtx, pNaNTestCase->Preferred, 0);
Laurence Lundblade8e5f42d2024-02-11 14:25:32 -0800627 QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700628 uErr = QCBORDecode_GetNext(&DCtx, &Item);
629 if(uErr != QCBOR_SUCCESS) {
630 return MakeTestResultCode(uTestIndex+100, 12, uErr);
631 }
632
633#ifndef QCBOR_DISABLE_FLOAT_HW_USE
634
635 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
636 if(uDecoded != pNaNTestCase->uDouble) {
637 return MakeTestResultCode(uTestIndex+100, 12, 200);
638 }
639#else /* QCBOR_DISABLE_FLOAT_HW_USE */
640 if(pNaNTestCase->Preferred.len == 5) {
641 if(Item.uDataType != QCBOR_TYPE_FLOAT) {
642 return MakeTestResultCode(uTestIndex, 4, 0);
643 }
644
645 uDecoded2 = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum);
646
647 if(uDecoded2 != pNaNTestCase->uSingle) {
648 return MakeTestResultCode(uTestIndex, 4, 0);
649 }
650 } else {
651 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
652 return MakeTestResultCode(uTestIndex, 4, 0);
653 }
654 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
655 if(uDecoded != pNaNTestCase->uDouble) {
656 return MakeTestResultCode(uTestIndex+100, 12, 200);
657 }
658 }
659#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
660
661 /* NaN Decode of Not Preferred */
662 QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0);
Laurence Lundblade8e5f42d2024-02-11 14:25:32 -0800663 QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700664 uErr = QCBORDecode_GetNext(&DCtx, &Item);
665 if(uErr != QCBOR_SUCCESS) {
666 return MakeTestResultCode(uTestIndex+100, 13, uErr);
667 }
668 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
669 if(uDecoded != pNaNTestCase->uDouble) {
670 return MakeTestResultCode(uTestIndex+100, 13, 200);
671 }
Laurence Lundblade240ca822024-01-16 11:11:00 -0700672
673
674 /* NaN Encode of DCBOR */
675 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade8e5f42d2024-02-11 14:25:32 -0800676 QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
Laurence Lundblade240ca822024-01-16 11:11:00 -0700677 QCBOREncode_SerializationdCBOR(&EnCtx);
678 QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
679 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
680 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladee75f5962024-02-15 17:51:32 -0800681 return MakeTestResultCode(uTestIndex+100, 14, uErr);;
Laurence Lundblade240ca822024-01-16 11:11:00 -0700682 }
683 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->DCBOR)) {
Laurence Lundbladee75f5962024-02-15 17:51:32 -0800684 return MakeTestResultCode(uTestIndex+100, 14, 200);
Laurence Lundblade240ca822024-01-16 11:11:00 -0700685 }
686
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700687 }
688
689 return 0;
Laurence Lundblade570fab52018-10-13 18:28:27 +0800690}
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700691
692
693
694/* Public function. See float_tests.h */
695int32_t
696HalfPrecisionAgainstRFCCodeTest(void)
697{
698 QCBORItem Item;
699 QCBORDecodeContext DC;
700 unsigned char pbHalfBytes[2];
701 uint8_t uHalfPrecInitialByte;
702 double d;
703 UsefulBuf_MAKE_STACK_UB(EncodedBytes, 3);
704 UsefulOutBuf UOB;
705 uint32_t uHalfP;
706
707
708 for(uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
709 pbHalfBytes[1] = (uint8_t)(uHalfP & 0xff);
710 pbHalfBytes[0] = (uint8_t)(uHalfP >> 8); /* uHalfP is always less than 0xffff */
711 d = decode_half(pbHalfBytes);
712
713 /* Construct the CBOR for the half-precision float by hand */
714 UsefulOutBuf_Init(&UOB, EncodedBytes);
715
716 uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); /* 0xf9 */
717 UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); /* initial byte */
718 UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP); /* argument */
719
720 /* Now parse the hand-constructed CBOR. This will invoke the
721 * conversion to a float
722 */
723 QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
724 QCBORDecode_GetNext(&DC, &Item);
725 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
726 return -1;
727 }
728
729 if(isnan(d)) {
730 /* The RFC code uses the native instructions which may or may not
731 * handle sNaN, qNaN and NaN payloads correctly. This test just
732 * makes sure it is a NaN and doesn't worry about the type of NaN
733 */
734 if(!isnan(Item.val.dfnum)) {
735 return -3;
736 }
737 } else {
738 if(Item.val.dfnum != d) {
739 return -2;
740 }
741 }
742 }
743 return 0;
744}
745
Laurence Lundblade585127a2020-07-15 03:25:24 -0700746#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700747
748
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700749/*
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700750 * Some encoded floating point numbers that are used for both
751 * encode and decode tests.
752 *
753 * [0.0, // Half
754 * 3.14, // Double
755 * 0.0, // Double
756 * NaN, // Double
757 * Infinity, // Double
758 * 0.0, // Half (Duplicate because of use in encode tests)
759 * 3.140000104904175, // Single
760 * 0.0, // Single
761 * NaN, // Single
762 * Infinity, // Single
763 * {100: 0.0, 101: 3.1415926, "euler": 2.718281828459045, 105: 0.0,
764 * 102: 0.0, 103: 3.141592502593994, "euler2": 2.7182817459106445, 106: 0.0}]
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700765 */
766static const uint8_t spExpectedFloats[] = {
767 0x8B,
768 0xF9, 0x00, 0x00,
769 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
770 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
771 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
772 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
773 0xF9, 0x00, 0x00,
774 0xFA, 0x40, 0x48, 0xF5, 0xC3,
775 0xFA, 0x00, 0x00, 0x00, 0x00,
776 0xFA, 0x7F, 0xC0, 0x00, 0x00,
777 0xFA, 0x7F, 0x80, 0x00, 0x00,
778 0xA8,
779 0x18, 0x64,
780 0xF9, 0x00, 0x00,
781 0x18, 0x65,
782 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
783 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
784 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
785 0x18, 0x69,
786 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
787 0x18, 0x66,
788 0xF9, 0x00, 0x00,
789 0x18, 0x67,
790 0xFA, 0x40, 0x49, 0x0F, 0xDA,
791 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
792 0xFA, 0x40, 0x2D, 0xF8, 0x54,
793 0x18, 0x6A,
794 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700795
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200796#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700797static const uint8_t spExpectedFloatsNoHalf[] = {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700798 0x8B,
799 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
800 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
801 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
802 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
803 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
804 0xFA, 0x00, 0x00, 0x00, 0x00,
805 0xFA, 0x40, 0x48, 0xF5, 0xC3,
806 0xFA, 0x00, 0x00, 0x00, 0x00,
807 0xFA, 0x7F, 0xC0, 0x00, 0x00,
808 0xFA, 0x7F, 0x80, 0x00, 0x00,
809 0xA8,
810 0x18, 0x64,
811 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812 0x18, 0x65,
813 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
814 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
815 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
816 0x18, 0x69,
817 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
818 0x18, 0x66,
819 0xFA, 0x00, 0x00, 0x00, 0x00,
820 0x18, 0x67,
821 0xFA, 0x40, 0x49, 0x0F, 0xDA,
822 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
823 0xFA, 0x40, 0x2D, 0xF8, 0x54,
824 0x18, 0x6A,
825 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700826
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700827
828/* Public function. See float_tests.h */
829int32_t
830GeneralFloatEncodeTests(void)
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700831{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700832 /* See FloatNumberTests() for tests that really cover lots of float values.
833 * Add new tests for new values or decode modes there.
834 * This test is primarily to cover all the float encode methods. */
835
836 UsefulBufC Encoded;
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700837 UsefulBufC ExpectedFloats;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700838 QCBORError uErr;
839
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700840#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700841 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloats));
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700842 ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700843 (void)spExpectedFloatsNoHalf; /* Avoid unused variable error */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700844#else
845 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloatsNoHalf));
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700846 ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloatsNoHalf);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700847 (void)spExpectedFloats; /* Avoid unused variable error */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700848#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700849
850 QCBOREncodeContext EC;
851 QCBOREncode_Init(&EC, OutBuffer);
852 QCBOREncode_OpenArray(&EC);
853
854 QCBOREncode_AddDouble(&EC, 0.0);
855 QCBOREncode_AddDouble(&EC, 3.14);
856 QCBOREncode_AddDoubleNoPreferred(&EC, 0.0);
857 QCBOREncode_AddDoubleNoPreferred(&EC, NAN);
858 QCBOREncode_AddDoubleNoPreferred(&EC, INFINITY);
859
860 QCBOREncode_AddFloat(&EC, 0.0);
861 QCBOREncode_AddFloat(&EC, 3.14f);
862 QCBOREncode_AddFloatNoPreferred(&EC, 0.0f);
863 QCBOREncode_AddFloatNoPreferred(&EC, NAN);
864 QCBOREncode_AddFloatNoPreferred(&EC, INFINITY);
865
866 QCBOREncode_OpenMap(&EC);
867
868 QCBOREncode_AddDoubleToMapN(&EC, 100, 0.0);
869 QCBOREncode_AddDoubleToMapN(&EC, 101, 3.1415926);
870 QCBOREncode_AddDoubleToMap(&EC, "euler", 2.71828182845904523536);
871 QCBOREncode_AddDoubleNoPreferredToMapN(&EC, 105, 0.0);
872
873 QCBOREncode_AddFloatToMapN(&EC, 102, 0.0f);
874 QCBOREncode_AddFloatToMapN(&EC, 103, 3.1415926f);
875 QCBOREncode_AddFloatToMap(&EC, "euler2", 2.71828182845904523536f);
876 QCBOREncode_AddFloatNoPreferredToMapN(&EC, 106, 0.0f);
877
878 QCBOREncode_CloseMap(&EC);
879 QCBOREncode_CloseArray(&EC);
880
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700881 uErr = QCBOREncode_Finish(&EC, &Encoded);
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700882 if(uErr) {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700883 return -1;
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700884 }
885
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700886 if(UsefulBuf_Compare(Encoded, ExpectedFloats)) {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700887 return -3;
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700888 }
889
890 return 0;
891}
892
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200893#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700894
895
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700896/* Public function. See float_tests.h */
897int32_t
898GeneralFloatDecodeTests(void)
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700899{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700900 /* See FloatNumberTests() for tests that really cover lots of float values */
901
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700902 QCBORItem Item;
903 QCBORError uErr;
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700904 QCBORDecodeContext DC;
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700905
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700906 UsefulBufC TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
907 QCBORDecode_Init(&DC, TestData, 0);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700908
909 QCBORDecode_GetNext(&DC, &Item);
910 if(Item.uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700911 return MakeTestResultCode(0, 1, 0);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700912 }
913
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700914 /* 0.0 half-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700915 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200916 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
917#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
918 || Item.uDataType != QCBOR_TYPE_DOUBLE
919 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700920#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
921 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200922#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
923 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700924 return MakeTestResultCode(0, 2, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700925 }
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700926
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700927 /* 3.14 double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700928 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200929 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
930#ifndef USEFULBUF_DISABLE_ALL_FLOAT
931 || Item.uDataType != QCBOR_TYPE_DOUBLE
932 || Item.val.dfnum != 3.14
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700933#else /* USEFULBUF_DISABLE_ALL_FLOAT */
934 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200935#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
936 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700937 return MakeTestResultCode(0, 3, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700938 }
939
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700940 /* 0.0 double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700941 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200942 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
943#ifndef USEFULBUF_DISABLE_ALL_FLOAT
944 || Item.uDataType != QCBOR_TYPE_DOUBLE
945 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700946#else /* USEFULBUF_DISABLE_ALL_FLOAT */
947 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200948#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
949 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700950 return MakeTestResultCode(0, 4, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700951 }
952
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700953 /* NaN double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700954 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200955 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
956#ifndef USEFULBUF_DISABLE_ALL_FLOAT
957 || Item.uDataType != QCBOR_TYPE_DOUBLE
958 || !isnan(Item.val.dfnum)
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700959#else /* USEFULBUF_DISABLE_ALL_FLOAT */
960 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200961#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
962 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700963 return MakeTestResultCode(0, 5, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700964 }
965
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700966 /* Infinity double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700967 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200968 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
969#ifndef USEFULBUF_DISABLE_ALL_FLOAT
970 || Item.uDataType != QCBOR_TYPE_DOUBLE
971 || Item.val.dfnum != INFINITY
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700972#else /* USEFULBUF_DISABLE_ALL_FLOAT */
973 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200974#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
975 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700976 return MakeTestResultCode(0, 6, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700977 }
978
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700979 /* 0.0 half-precision (again) */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700980 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200981 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
982#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
983 || Item.uDataType != QCBOR_TYPE_DOUBLE
984 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700985#else /* USEFULBUF_DISABLE_ALL_FLOAT */
986 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200987#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
988 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700989 return MakeTestResultCode(0, 7, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700990 }
991
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700992 /* 3.140000104904175 single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700993 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200994 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
995#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700996#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200997 || Item.uDataType != QCBOR_TYPE_DOUBLE
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700998 || 3.1400001049041748 != Item.val.dfnum
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700999#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001000 || Item.uDataType != QCBOR_TYPE_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001001 || 3.140000f != Item.val.fnum
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001002#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1003#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1004 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001005#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1006 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001007 return MakeTestResultCode(0, 8, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001008 }
1009
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001010 /* 0.0 single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001011 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001012 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1013#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001014#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1015 || Item.uDataType != QCBOR_TYPE_DOUBLE
1016 || Item.val.dfnum != 0.0
1017#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001018 || Item.uDataType != QCBOR_TYPE_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001019 || Item.val.fnum != 0.0f
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001020#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1021#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1022 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001023#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1024 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001025 return MakeTestResultCode(0, 9, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001026 }
1027
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001028 /* NaN single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001029 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001030 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1031#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001032#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1033 || Item.uDataType != QCBOR_TYPE_DOUBLE
1034 || !isnan(Item.val.dfnum)
1035#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001036 || Item.uDataType != QCBOR_TYPE_FLOAT
1037 || !isnan(Item.val.fnum)
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001038#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1039#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1040 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001041#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1042 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001043 return MakeTestResultCode(0, 10, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001044 }
1045
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001046 /* Infinity single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001047 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001048 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1049#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001050#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1051 || Item.uDataType != QCBOR_TYPE_DOUBLE
1052 || Item.val.dfnum != INFINITY
1053#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001054 || Item.uDataType != QCBOR_TYPE_FLOAT
1055 || Item.val.fnum != INFINITY
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001056#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1057#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1058 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001059#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1060 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001061 return MakeTestResultCode(0, 11, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001062 }
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001063 /* Sufficent test coverage. Don't need to decode the rest. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001064
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001065
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001066#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001067 /* Now tests for spiffy decode main function */
1068 TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001069 double d;
1070 QCBORDecode_Init(&DC, TestData, 0);
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07001071 QCBORDecode_EnterArray(&DC, NULL);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001072
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001073 /* 0.0 half-precision */
1074 QCBORDecode_GetDouble(&DC, &d);
1075 uErr = QCBORDecode_GetAndResetError(&DC);
1076 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001077#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001078 || d != 0.0
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001079#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001080 ) {
1081 return MakeTestResultCode(1, 1, uErr);
1082 }
1083
1084 /* 3.14 double-precision */
1085 QCBORDecode_GetDouble(&DC, &d);
1086 uErr = QCBORDecode_GetAndResetError(&DC);
1087 if(uErr != QCBOR_SUCCESS || d != 3.14) {
1088 return MakeTestResultCode(1, 2, uErr);
1089 }
1090
1091 /* 0.0 double-precision */
1092 QCBORDecode_GetDouble(&DC, &d);
1093 uErr = QCBORDecode_GetAndResetError(&DC);
1094 if(uErr != QCBOR_SUCCESS || d != 0.0) {
1095 return MakeTestResultCode(1, 3, uErr);
1096 }
1097
1098 /* NaN double-precision */
1099 QCBORDecode_GetDouble(&DC, &d);
1100 uErr = QCBORDecode_GetAndResetError(&DC);
1101 if(uErr != QCBOR_SUCCESS || !isnan(d)) {
1102 return MakeTestResultCode(1, 4, uErr);
1103 }
1104
1105 /* Infinity double-precision */
1106 QCBORDecode_GetDouble(&DC, &d);
1107 uErr = QCBORDecode_GetAndResetError(&DC);
1108 if(uErr != QCBOR_SUCCESS || d != INFINITY) {
1109 return MakeTestResultCode(1, 5, uErr);
1110 }
1111
1112 /* 0.0 half-precision */
1113 QCBORDecode_GetDouble(&DC, &d);
1114 uErr = QCBORDecode_GetAndResetError(&DC);
1115 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
1116#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1117 || d != 0.0
1118#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
1119 ) {
1120 return MakeTestResultCode(1, 6, uErr);
1121 }
1122
1123 /* 3.140000104904175 single-precision */
1124 QCBORDecode_GetDouble(&DC, &d);
1125 uErr = QCBORDecode_GetAndResetError(&DC);
1126 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1127#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1128 || d != 3.140000104904175
1129#endif
1130 ) {
1131 return MakeTestResultCode(1, 7, uErr);
1132 }
1133
1134 /* 0.0 single-precision */
1135 QCBORDecode_GetDouble(&DC, &d);
1136 uErr = QCBORDecode_GetAndResetError(&DC);
1137 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1138#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1139 || d != 0.0
1140#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1141 ) {
1142 return MakeTestResultCode(1, 8, uErr);
1143 }
1144
1145 /* NaN single-precision */
1146 QCBORDecode_GetDouble(&DC, &d);
1147 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1148#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1149 || !isnan(d)
1150#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1151 ) {
1152 return MakeTestResultCode(1, 9, uErr);
1153 }
1154
1155 /* Infinity single-precision */
1156 QCBORDecode_GetDouble(&DC, &d);
1157 uErr = QCBORDecode_GetAndResetError(&DC);
1158 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1159#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1160 || d != INFINITY
1161#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1162 ) {
1163 return MakeTestResultCode(1, 10, uErr);
1164 }
1165
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001166#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001167
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001168 return 0;
1169}
1170
1171
Laurence Lundbladed711fb22018-09-26 14:35:22 -07001172
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001173#ifdef NAN_EXPERIMENT
1174/*
1175 Code for checking what the double to float cast does with
1176 NaNs. Not run as part of tests. Keep it around to
1177 be able to check various platforms and CPUs.
1178 */
1179
1180#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
1181#define DOUBLE_NUM_EXPONENT_BITS (11)
1182#define DOUBLE_NUM_SIGN_BITS (1)
1183
1184#define DOUBLE_SIGNIFICAND_SHIFT (0)
1185#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS)
1186#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
1187
1188#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits
1189#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
1190#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
1191#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
1192
1193
1194static int NaNExperiments() {
1195 double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
1196 double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
1197 double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001198
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001199 float f1 = (float)dqNaN;
1200 float f2 = (float)dsNaN;
1201 float f3 = (float)dqNaNPayload;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001202
1203
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001204 uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
1205 uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
1206 uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001207
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001208 // Result of this on x86 is that every NaN is a qNaN. The intel
1209 // CVTSD2SS instruction ignores the NaN payload and even converts
1210 // a sNaN to a qNaN.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001211
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001212 return 0;
1213}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001214#endif /* NAN_EXPERIMENT */