blob: 3df8639ee41bb8ffea4d4a4f1a575432c2202f9c [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 Lundbladebf8e1cf2024-01-17 11:58:24 -0700400 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 Lundbladee026f4f2024-01-18 13:48:34 -0700417
418 // 9223372036854774784
419 if(pTestCase->dNumber == 1.7976931348623157e308 ||
420 uTestIndex == 77) {
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700421 uErr = 99; /* For setting break points for particular tests */
422 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800423
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700424 /* Number Encode of Preferred */
425 QCBOREncode_Init(&EnCtx, TestOutBuffer);
426 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
427 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800428
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700429 if(uErr != QCBOR_SUCCESS) {
430 return MakeTestResultCode(uTestIndex, 1, uErr);;
431 }
432 if(UsefulBuf_Compare(TestOutput, pTestCase->Preferred)) {
433 return MakeTestResultCode(uTestIndex, 1, 200);
434 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700435
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700436 /* Number Encode of Not Preferred */
437 QCBOREncode_Init(&EnCtx, TestOutBuffer);
438 QCBOREncode_AddDoubleNoPreferred(&EnCtx, pTestCase->dNumber);
439 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
Laurence Lundblade68a13352018-09-23 02:19:54 -0700440
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700441 if(uErr != QCBOR_SUCCESS) {
442 return MakeTestResultCode(uTestIndex, 2, uErr);;
443 }
444 if(UsefulBuf_Compare(TestOutput, pTestCase->NotPreferred)) {
445 return MakeTestResultCode(uTestIndex, 2, 200);
446 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800447
Laurence Lundblade240ca822024-01-16 11:11:00 -0700448 /* Number Encode of CDE */
449 QCBOREncode_Init(&EnCtx, TestOutBuffer);
450 QCBOREncode_SerializationCDE(&EnCtx);
451 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
452 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
453
454 if(uErr != QCBOR_SUCCESS) {
455 return MakeTestResultCode(uTestIndex, 20, uErr);;
456 }
457 if(UsefulBuf_Compare(TestOutput, pTestCase->CDE)) {
458 return MakeTestResultCode(uTestIndex, 21, 200);
459 }
460
461 /* Number Encode of dCBOR */
462 QCBOREncode_Init(&EnCtx, TestOutBuffer);
463 QCBOREncode_SerializationdCBOR(&EnCtx);
464 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
465 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
466
467 if(uErr != QCBOR_SUCCESS) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700468 return MakeTestResultCode(uTestIndex, 22, uErr);;
Laurence Lundblade240ca822024-01-16 11:11:00 -0700469 }
470 if(UsefulBuf_Compare(TestOutput, pTestCase->DCBOR)) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700471 return MakeTestResultCode(uTestIndex, 23, 200);
472 }
473
474 if(pTestCase->fNumber != 0) {
475 QCBOREncode_Init(&EnCtx, TestOutBuffer);
476 QCBOREncode_SerializationdCBOR(&EnCtx);
477 QCBOREncode_AddFloat(&EnCtx, pTestCase->fNumber);
478 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
479
480 if(uErr != QCBOR_SUCCESS) {
481 return MakeTestResultCode(uTestIndex, 24, uErr);;
482 }
483 if(UsefulBuf_Compare(TestOutput, pTestCase->DCBOR)) {
484 return MakeTestResultCode(uTestIndex, 25, 200);
485 }
Laurence Lundblade240ca822024-01-16 11:11:00 -0700486 }
487
488
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700489 /* Number Decode of Preferred */
490 QCBORDecode_Init(&DCtx, pTestCase->Preferred, 0);
491 uErr = QCBORDecode_GetNext(&DCtx, &Item);
492 if(uErr != QCBOR_SUCCESS) {
493 return MakeTestResultCode(uTestIndex, 3, uErr);;
494 }
495#ifndef QCBOR_DISABLE_FLOAT_HW_USE
496 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
497 return MakeTestResultCode(uTestIndex, 4, 0);
498 }
499 if(isnan(pTestCase->dNumber)) {
500 if(!isnan(Item.val.dfnum)) {
501 return MakeTestResultCode(uTestIndex, 5, 0);
502 }
503 } else {
504 if(Item.val.dfnum != pTestCase->dNumber) {
505 return MakeTestResultCode(uTestIndex, 6, 0);
506 }
507 }
508#else /* QCBOR_DISABLE_FLOAT_HW_USE */
509 /* When QCBOR_DISABLE_FLOAT_HW_USE is set, single-precision is not
510 * converted to double when decoding, so test differently. len == 5
511 * indicates single-precision in the encoded CBOR. */
512 if(pTestCase->Preferred.len == 5) {
513 if(Item.uDataType != QCBOR_TYPE_FLOAT) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700514 return MakeTestResultCode(uTestIndex, 41, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700515 }
516 if(isnan(pTestCase->dNumber)) {
517 if(!isnan(Item.val.fnum)) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700518 return MakeTestResultCode(uTestIndex, 51, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700519 }
520 } else {
521 if(Item.val.fnum != pTestCase->fNumber) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700522 return MakeTestResultCode(uTestIndex, 61, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700523 }
524 }
525 } else {
526 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700527 return MakeTestResultCode(uTestIndex, 42, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700528 }
529 if(isnan(pTestCase->dNumber)) {
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700530 if(!isnan(Item.val.dfnum)) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700531 return MakeTestResultCode(uTestIndex, 52, 0);
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700532 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700533 } else {
534 if(Item.val.dfnum != pTestCase->dNumber) {
Laurence Lundbladebf8e1cf2024-01-17 11:58:24 -0700535 return MakeTestResultCode(uTestIndex, 62, 0);
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700536 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700537 }
538 }
539#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700540
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700541 /* Number Decode of Not Preferred */
542 QCBORDecode_Init(&DCtx, pTestCase->NotPreferred, 0);
543 uErr = QCBORDecode_GetNext(&DCtx, &Item);
544 if(uErr != QCBOR_SUCCESS) {
545 return MakeTestResultCode(uTestIndex, 7, uErr);;
546 }
547 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
548 return MakeTestResultCode(uTestIndex, 8, 0);
549 }
550 if(isnan(pTestCase->dNumber)) {
551 if(!isnan(Item.val.dfnum)) {
552 return MakeTestResultCode(uTestIndex, 9, 0);
553 }
554 } else {
555 if(Item.val.dfnum != pTestCase->dNumber) {
556 return MakeTestResultCode(uTestIndex, 10, 0);
557 }
558 }
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700559
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700560 }
561
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700562 /* Test a variety of NaNs with payloads */
563 for(uTestIndex = 0; NaNTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
564 pNaNTestCase = &NaNTestCases[uTestIndex];
565
566
567 if(uTestIndex == 4) {
568 uErr = 99; /* For setting break points for particular tests */
569 }
570
571 /* NaN Encode of Preferred */
572 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade8e5f42d2024-02-11 14:25:32 -0800573 QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700574 QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
575 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
576 if(uErr != QCBOR_SUCCESS) {
577 return MakeTestResultCode(uTestIndex+100, 10, uErr);;
578 }
579 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) {
580 return MakeTestResultCode(uTestIndex+100, 10, 200);
581 }
582
583#ifdef QCBOR_COMPARE_TO_HW_NAN_CONVERSION
584 {
585 /* This test is off by default. It's purpose is to check
586 * QCBOR's mask-n-shift implementation against the HW/CPU
587 * instructions that do conversion between double and single.
588 * It is off because it is only used on occasion to verify
589 * QCBOR and because it is suspected that some HW/CPU does
590 * implement this correctly. NaN payloads are an obscure
591 * feature. */
592 float f;
593 double d, d2;
594
595 d = UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uNumber);
596
597 /* Cast the double to a single and then back to a double and
598 * see if they are equal. If so, then the NaN payload doesn't
599 * have any bits that are lost when converting to single and
600 * it can be safely converted.
601 *
602 * This test can't be done for half-precision because it is
603 * not widely supported.
604 */
605 f = (float)d;
606 d2 = (double)f;
607
608 /* The length of encoded doubles is 9, singles 5 and halves
609 * 3. If there are NaN payload bits that can't be converted,
610 * then the length must be 9.
611 */
612 if((uint64_t)d != (uint64_t)d2 && pNaNTestCase->Preferred.len != 9) {
613 /* QCBOR conversion not the same as HW conversion */
614 return MakeTestResultCode(uTestIndex, 9, 200);
615 }
616 }
617#endif /* QCBOR_COMPARE_TO_HW_NAN_CONVERSION */
618
619
620 /* NaN Encode of Not Preferred */
621 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade8e5f42d2024-02-11 14:25:32 -0800622 QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700623 QCBOREncode_AddDoubleNoPreferred(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
624 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
625 if(uErr != QCBOR_SUCCESS) {
626 return MakeTestResultCode(uTestIndex+100, 11, uErr);;
627 }
628 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
629 return MakeTestResultCode(uTestIndex+100, 11, 200);
630 }
631
Laurence Lundblade240ca822024-01-16 11:11:00 -0700632 /* NaN Decode of Not Preferred */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700633 QCBORDecode_Init(&DCtx, pNaNTestCase->Preferred, 0);
Laurence Lundblade8e5f42d2024-02-11 14:25:32 -0800634 QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700635 uErr = QCBORDecode_GetNext(&DCtx, &Item);
636 if(uErr != QCBOR_SUCCESS) {
637 return MakeTestResultCode(uTestIndex+100, 12, uErr);
638 }
639
640#ifndef QCBOR_DISABLE_FLOAT_HW_USE
641
642 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
643 if(uDecoded != pNaNTestCase->uDouble) {
644 return MakeTestResultCode(uTestIndex+100, 12, 200);
645 }
646#else /* QCBOR_DISABLE_FLOAT_HW_USE */
647 if(pNaNTestCase->Preferred.len == 5) {
648 if(Item.uDataType != QCBOR_TYPE_FLOAT) {
649 return MakeTestResultCode(uTestIndex, 4, 0);
650 }
651
652 uDecoded2 = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum);
653
654 if(uDecoded2 != pNaNTestCase->uSingle) {
655 return MakeTestResultCode(uTestIndex, 4, 0);
656 }
657 } else {
658 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
659 return MakeTestResultCode(uTestIndex, 4, 0);
660 }
661 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
662 if(uDecoded != pNaNTestCase->uDouble) {
663 return MakeTestResultCode(uTestIndex+100, 12, 200);
664 }
665 }
666#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
667
668 /* NaN Decode of Not Preferred */
669 QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0);
Laurence Lundblade8e5f42d2024-02-11 14:25:32 -0800670 QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700671 uErr = QCBORDecode_GetNext(&DCtx, &Item);
672 if(uErr != QCBOR_SUCCESS) {
673 return MakeTestResultCode(uTestIndex+100, 13, uErr);
674 }
675 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
676 if(uDecoded != pNaNTestCase->uDouble) {
677 return MakeTestResultCode(uTestIndex+100, 13, 200);
678 }
Laurence Lundblade240ca822024-01-16 11:11:00 -0700679
680
681 /* NaN Encode of DCBOR */
682 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade8e5f42d2024-02-11 14:25:32 -0800683 QCBOREncode_Allow(&EnCtx, QCBOR_ENCODE_ALLOW_NAN_PAYLOAD);
Laurence Lundblade240ca822024-01-16 11:11:00 -0700684 QCBOREncode_SerializationdCBOR(&EnCtx);
685 QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
686 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
687 if(uErr != QCBOR_SUCCESS) {
688 return MakeTestResultCode(uTestIndex+100, 11, uErr);;
689 }
690 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->DCBOR)) {
691 return MakeTestResultCode(uTestIndex+100, 11, 200);
692 }
693
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700694 }
695
696 return 0;
Laurence Lundblade570fab52018-10-13 18:28:27 +0800697}
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700698
699
700
701/* Public function. See float_tests.h */
702int32_t
703HalfPrecisionAgainstRFCCodeTest(void)
704{
705 QCBORItem Item;
706 QCBORDecodeContext DC;
707 unsigned char pbHalfBytes[2];
708 uint8_t uHalfPrecInitialByte;
709 double d;
710 UsefulBuf_MAKE_STACK_UB(EncodedBytes, 3);
711 UsefulOutBuf UOB;
712 uint32_t uHalfP;
713
714
715 for(uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
716 pbHalfBytes[1] = (uint8_t)(uHalfP & 0xff);
717 pbHalfBytes[0] = (uint8_t)(uHalfP >> 8); /* uHalfP is always less than 0xffff */
718 d = decode_half(pbHalfBytes);
719
720 /* Construct the CBOR for the half-precision float by hand */
721 UsefulOutBuf_Init(&UOB, EncodedBytes);
722
723 uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); /* 0xf9 */
724 UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); /* initial byte */
725 UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP); /* argument */
726
727 /* Now parse the hand-constructed CBOR. This will invoke the
728 * conversion to a float
729 */
730 QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
731 QCBORDecode_GetNext(&DC, &Item);
732 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
733 return -1;
734 }
735
736 if(isnan(d)) {
737 /* The RFC code uses the native instructions which may or may not
738 * handle sNaN, qNaN and NaN payloads correctly. This test just
739 * makes sure it is a NaN and doesn't worry about the type of NaN
740 */
741 if(!isnan(Item.val.dfnum)) {
742 return -3;
743 }
744 } else {
745 if(Item.val.dfnum != d) {
746 return -2;
747 }
748 }
749 }
750 return 0;
751}
752
Laurence Lundblade585127a2020-07-15 03:25:24 -0700753#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700754
755
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700756/*
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700757 * Some encoded floating point numbers that are used for both
758 * encode and decode tests.
759 *
760 * [0.0, // Half
761 * 3.14, // Double
762 * 0.0, // Double
763 * NaN, // Double
764 * Infinity, // Double
765 * 0.0, // Half (Duplicate because of use in encode tests)
766 * 3.140000104904175, // Single
767 * 0.0, // Single
768 * NaN, // Single
769 * Infinity, // Single
770 * {100: 0.0, 101: 3.1415926, "euler": 2.718281828459045, 105: 0.0,
771 * 102: 0.0, 103: 3.141592502593994, "euler2": 2.7182817459106445, 106: 0.0}]
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700772 */
773static const uint8_t spExpectedFloats[] = {
774 0x8B,
775 0xF9, 0x00, 0x00,
776 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
777 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
778 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
779 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
780 0xF9, 0x00, 0x00,
781 0xFA, 0x40, 0x48, 0xF5, 0xC3,
782 0xFA, 0x00, 0x00, 0x00, 0x00,
783 0xFA, 0x7F, 0xC0, 0x00, 0x00,
784 0xFA, 0x7F, 0x80, 0x00, 0x00,
785 0xA8,
786 0x18, 0x64,
787 0xF9, 0x00, 0x00,
788 0x18, 0x65,
789 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
790 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
791 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
792 0x18, 0x69,
793 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
794 0x18, 0x66,
795 0xF9, 0x00, 0x00,
796 0x18, 0x67,
797 0xFA, 0x40, 0x49, 0x0F, 0xDA,
798 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
799 0xFA, 0x40, 0x2D, 0xF8, 0x54,
800 0x18, 0x6A,
801 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700802
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200803#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700804static const uint8_t spExpectedFloatsNoHalf[] = {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700805 0x8B,
806 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
807 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
808 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
809 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0xFA, 0x00, 0x00, 0x00, 0x00,
812 0xFA, 0x40, 0x48, 0xF5, 0xC3,
813 0xFA, 0x00, 0x00, 0x00, 0x00,
814 0xFA, 0x7F, 0xC0, 0x00, 0x00,
815 0xFA, 0x7F, 0x80, 0x00, 0x00,
816 0xA8,
817 0x18, 0x64,
818 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
819 0x18, 0x65,
820 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
821 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
822 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
823 0x18, 0x69,
824 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
825 0x18, 0x66,
826 0xFA, 0x00, 0x00, 0x00, 0x00,
827 0x18, 0x67,
828 0xFA, 0x40, 0x49, 0x0F, 0xDA,
829 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
830 0xFA, 0x40, 0x2D, 0xF8, 0x54,
831 0x18, 0x6A,
832 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700833
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700834
835/* Public function. See float_tests.h */
836int32_t
837GeneralFloatEncodeTests(void)
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700838{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700839 /* See FloatNumberTests() for tests that really cover lots of float values.
840 * Add new tests for new values or decode modes there.
841 * This test is primarily to cover all the float encode methods. */
842
843 UsefulBufC Encoded;
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700844 UsefulBufC ExpectedFloats;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700845 QCBORError uErr;
846
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700847#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700848 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloats));
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700849 ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700850 (void)spExpectedFloatsNoHalf; /* Avoid unused variable error */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700851#else
852 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloatsNoHalf));
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700853 ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloatsNoHalf);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700854 (void)spExpectedFloats; /* Avoid unused variable error */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700855#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700856
857 QCBOREncodeContext EC;
858 QCBOREncode_Init(&EC, OutBuffer);
859 QCBOREncode_OpenArray(&EC);
860
861 QCBOREncode_AddDouble(&EC, 0.0);
862 QCBOREncode_AddDouble(&EC, 3.14);
863 QCBOREncode_AddDoubleNoPreferred(&EC, 0.0);
864 QCBOREncode_AddDoubleNoPreferred(&EC, NAN);
865 QCBOREncode_AddDoubleNoPreferred(&EC, INFINITY);
866
867 QCBOREncode_AddFloat(&EC, 0.0);
868 QCBOREncode_AddFloat(&EC, 3.14f);
869 QCBOREncode_AddFloatNoPreferred(&EC, 0.0f);
870 QCBOREncode_AddFloatNoPreferred(&EC, NAN);
871 QCBOREncode_AddFloatNoPreferred(&EC, INFINITY);
872
873 QCBOREncode_OpenMap(&EC);
874
875 QCBOREncode_AddDoubleToMapN(&EC, 100, 0.0);
876 QCBOREncode_AddDoubleToMapN(&EC, 101, 3.1415926);
877 QCBOREncode_AddDoubleToMap(&EC, "euler", 2.71828182845904523536);
878 QCBOREncode_AddDoubleNoPreferredToMapN(&EC, 105, 0.0);
879
880 QCBOREncode_AddFloatToMapN(&EC, 102, 0.0f);
881 QCBOREncode_AddFloatToMapN(&EC, 103, 3.1415926f);
882 QCBOREncode_AddFloatToMap(&EC, "euler2", 2.71828182845904523536f);
883 QCBOREncode_AddFloatNoPreferredToMapN(&EC, 106, 0.0f);
884
885 QCBOREncode_CloseMap(&EC);
886 QCBOREncode_CloseArray(&EC);
887
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700888 uErr = QCBOREncode_Finish(&EC, &Encoded);
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700889 if(uErr) {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700890 return -1;
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700891 }
892
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700893 if(UsefulBuf_Compare(Encoded, ExpectedFloats)) {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700894 return -3;
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700895 }
896
897 return 0;
898}
899
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200900#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700901
902
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700903/* Public function. See float_tests.h */
904int32_t
905GeneralFloatDecodeTests(void)
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700906{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700907 /* See FloatNumberTests() for tests that really cover lots of float values */
908
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700909 QCBORItem Item;
910 QCBORError uErr;
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700911 QCBORDecodeContext DC;
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700912
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700913 UsefulBufC TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
914 QCBORDecode_Init(&DC, TestData, 0);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700915
916 QCBORDecode_GetNext(&DC, &Item);
917 if(Item.uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700918 return MakeTestResultCode(0, 1, 0);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700919 }
920
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700921 /* 0.0 half-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700922 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200923 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
924#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
925 || Item.uDataType != QCBOR_TYPE_DOUBLE
926 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700927#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
928 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200929#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
930 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700931 return MakeTestResultCode(0, 2, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700932 }
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700933
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700934 /* 3.14 double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700935 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200936 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
937#ifndef USEFULBUF_DISABLE_ALL_FLOAT
938 || Item.uDataType != QCBOR_TYPE_DOUBLE
939 || Item.val.dfnum != 3.14
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700940#else /* USEFULBUF_DISABLE_ALL_FLOAT */
941 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200942#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
943 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700944 return MakeTestResultCode(0, 3, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700945 }
946
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700947 /* 0.0 double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700948 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200949 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
950#ifndef USEFULBUF_DISABLE_ALL_FLOAT
951 || Item.uDataType != QCBOR_TYPE_DOUBLE
952 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700953#else /* USEFULBUF_DISABLE_ALL_FLOAT */
954 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200955#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
956 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700957 return MakeTestResultCode(0, 4, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700958 }
959
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700960 /* NaN double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700961 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200962 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
963#ifndef USEFULBUF_DISABLE_ALL_FLOAT
964 || Item.uDataType != QCBOR_TYPE_DOUBLE
965 || !isnan(Item.val.dfnum)
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700966#else /* USEFULBUF_DISABLE_ALL_FLOAT */
967 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200968#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
969 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700970 return MakeTestResultCode(0, 5, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700971 }
972
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700973 /* Infinity double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700974 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200975 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
976#ifndef USEFULBUF_DISABLE_ALL_FLOAT
977 || Item.uDataType != QCBOR_TYPE_DOUBLE
978 || Item.val.dfnum != INFINITY
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700979#else /* USEFULBUF_DISABLE_ALL_FLOAT */
980 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200981#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
982 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700983 return MakeTestResultCode(0, 6, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700984 }
985
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700986 /* 0.0 half-precision (again) */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700987 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200988 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
989#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
990 || Item.uDataType != QCBOR_TYPE_DOUBLE
991 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700992#else /* USEFULBUF_DISABLE_ALL_FLOAT */
993 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200994#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
995 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700996 return MakeTestResultCode(0, 7, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700997 }
998
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700999 /* 3.140000104904175 single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001000 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001001 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1002#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001003#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001004 || Item.uDataType != QCBOR_TYPE_DOUBLE
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001005 || 3.1400001049041748 != Item.val.dfnum
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001006#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001007 || Item.uDataType != QCBOR_TYPE_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001008 || 3.140000f != Item.val.fnum
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001009#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1010#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1011 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001012#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1013 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001014 return MakeTestResultCode(0, 8, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001015 }
1016
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001017 /* 0.0 single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001018 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001019 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1020#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001021#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1022 || Item.uDataType != QCBOR_TYPE_DOUBLE
1023 || Item.val.dfnum != 0.0
1024#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001025 || Item.uDataType != QCBOR_TYPE_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001026 || Item.val.fnum != 0.0f
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001027#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1028#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1029 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001030#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1031 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001032 return MakeTestResultCode(0, 9, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001033 }
1034
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001035 /* NaN single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001036 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001037 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1038#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001039#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1040 || Item.uDataType != QCBOR_TYPE_DOUBLE
1041 || !isnan(Item.val.dfnum)
1042#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001043 || Item.uDataType != QCBOR_TYPE_FLOAT
1044 || !isnan(Item.val.fnum)
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001045#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1046#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1047 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001048#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1049 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001050 return MakeTestResultCode(0, 10, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001051 }
1052
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001053 /* Infinity single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001054 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001055 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1056#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001057#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1058 || Item.uDataType != QCBOR_TYPE_DOUBLE
1059 || Item.val.dfnum != INFINITY
1060#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001061 || Item.uDataType != QCBOR_TYPE_FLOAT
1062 || Item.val.fnum != INFINITY
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001063#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1064#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1065 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001066#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1067 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001068 return MakeTestResultCode(0, 11, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001069 }
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001070 /* Sufficent test coverage. Don't need to decode the rest. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001071
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001072
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001073#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001074 /* Now tests for spiffy decode main function */
1075 TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001076 double d;
1077 QCBORDecode_Init(&DC, TestData, 0);
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07001078 QCBORDecode_EnterArray(&DC, NULL);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001079
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001080 /* 0.0 half-precision */
1081 QCBORDecode_GetDouble(&DC, &d);
1082 uErr = QCBORDecode_GetAndResetError(&DC);
1083 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001084#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001085 || d != 0.0
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001086#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001087 ) {
1088 return MakeTestResultCode(1, 1, uErr);
1089 }
1090
1091 /* 3.14 double-precision */
1092 QCBORDecode_GetDouble(&DC, &d);
1093 uErr = QCBORDecode_GetAndResetError(&DC);
1094 if(uErr != QCBOR_SUCCESS || d != 3.14) {
1095 return MakeTestResultCode(1, 2, uErr);
1096 }
1097
1098 /* 0.0 double-precision */
1099 QCBORDecode_GetDouble(&DC, &d);
1100 uErr = QCBORDecode_GetAndResetError(&DC);
1101 if(uErr != QCBOR_SUCCESS || d != 0.0) {
1102 return MakeTestResultCode(1, 3, uErr);
1103 }
1104
1105 /* NaN double-precision */
1106 QCBORDecode_GetDouble(&DC, &d);
1107 uErr = QCBORDecode_GetAndResetError(&DC);
1108 if(uErr != QCBOR_SUCCESS || !isnan(d)) {
1109 return MakeTestResultCode(1, 4, uErr);
1110 }
1111
1112 /* Infinity double-precision */
1113 QCBORDecode_GetDouble(&DC, &d);
1114 uErr = QCBORDecode_GetAndResetError(&DC);
1115 if(uErr != QCBOR_SUCCESS || d != INFINITY) {
1116 return MakeTestResultCode(1, 5, uErr);
1117 }
1118
1119 /* 0.0 half-precision */
1120 QCBORDecode_GetDouble(&DC, &d);
1121 uErr = QCBORDecode_GetAndResetError(&DC);
1122 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
1123#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1124 || d != 0.0
1125#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
1126 ) {
1127 return MakeTestResultCode(1, 6, uErr);
1128 }
1129
1130 /* 3.140000104904175 single-precision */
1131 QCBORDecode_GetDouble(&DC, &d);
1132 uErr = QCBORDecode_GetAndResetError(&DC);
1133 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1134#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1135 || d != 3.140000104904175
1136#endif
1137 ) {
1138 return MakeTestResultCode(1, 7, uErr);
1139 }
1140
1141 /* 0.0 single-precision */
1142 QCBORDecode_GetDouble(&DC, &d);
1143 uErr = QCBORDecode_GetAndResetError(&DC);
1144 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1145#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1146 || d != 0.0
1147#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1148 ) {
1149 return MakeTestResultCode(1, 8, uErr);
1150 }
1151
1152 /* NaN single-precision */
1153 QCBORDecode_GetDouble(&DC, &d);
1154 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1155#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1156 || !isnan(d)
1157#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1158 ) {
1159 return MakeTestResultCode(1, 9, uErr);
1160 }
1161
1162 /* Infinity single-precision */
1163 QCBORDecode_GetDouble(&DC, &d);
1164 uErr = QCBORDecode_GetAndResetError(&DC);
1165 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1166#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1167 || d != INFINITY
1168#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1169 ) {
1170 return MakeTestResultCode(1, 10, uErr);
1171 }
1172
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001173#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001174
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001175 return 0;
1176}
1177
1178
Laurence Lundbladed711fb22018-09-26 14:35:22 -07001179
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001180#ifdef NAN_EXPERIMENT
1181/*
1182 Code for checking what the double to float cast does with
1183 NaNs. Not run as part of tests. Keep it around to
1184 be able to check various platforms and CPUs.
1185 */
1186
1187#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
1188#define DOUBLE_NUM_EXPONENT_BITS (11)
1189#define DOUBLE_NUM_SIGN_BITS (1)
1190
1191#define DOUBLE_SIGNIFICAND_SHIFT (0)
1192#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS)
1193#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
1194
1195#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits
1196#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
1197#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
1198#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
1199
1200
1201static int NaNExperiments() {
1202 double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
1203 double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
1204 double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001205
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001206 float f1 = (float)dqNaN;
1207 float f2 = (float)dsNaN;
1208 float f3 = (float)dqNaNPayload;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001209
1210
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001211 uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
1212 uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
1213 uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001214
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001215 // Result of this on x86 is that every NaN is a qNaN. The intel
1216 // CVTSD2SS instruction ignores the NaN payload and even converts
1217 // a sNaN to a qNaN.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001218
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001219 return 0;
1220}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001221#endif /* NAN_EXPERIMENT */