blob: d36ef6160e6f7d0f77437adc279571750c8b332a [file] [log] [blame]
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001/* ==========================================================================
2 * float_tests.c -- tests for float and conversion to/from half-precision
3 *
4 * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved.
5 * Copyright (c) 2021, Arm Limited. All rights reserved.
6 *
7 * SPDX-License-Identifier: BSD-3-Clause
8 *
Laurence Lundbladee8f58162024-08-22 10:30:08 -07009 * See BSD-3-Clause license in file named "LICENSE"
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070010 *
11 * Created on 9/19/18
12 * ========================================================================= */
Laurence Lundblade68a13352018-09-23 02:19:54 -070013
Laurence Lundblade2aa0b572020-07-16 19:48:42 -070014
15#include "float_tests.h"
Laurence Lundblade7596eef2024-12-21 10:08:32 -070016#include "qcbor/qcbor_main_encode.h"
17#include "qcbor/qcbor_number_encode.h"
Laurence Lundblade02fcf312020-07-17 02:49:46 -070018#include "qcbor/qcbor_decode.h"
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -070019#include "qcbor/qcbor_spiffy_decode.h"
Laurence Lundblade33ed26f2024-11-24 10:26:43 -080020#include "qcbor/qcbor_number_decode.h"
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070021#include <math.h> /* For INFINITY and NAN and isnan() */
Laurence Lundblade585127a2020-07-15 03:25:24 -070022
Laurence Lundblade16a207a2021-09-18 17:22:46 -070023
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070024
25/* Make a test results code that includes three components. Return code
26 * is xxxyyyzzz where zz is the error code, yy is the test number and
27 * zz is check being performed
Laurence Lundblade16a207a2021-09-18 17:22:46 -070028 */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070029static inline int32_t
30MakeTestResultCode(uint32_t uTestCase,
31 uint32_t uTestNumber,
32 QCBORError uErrorCode)
Laurence Lundblade16a207a2021-09-18 17:22:46 -070033{
34 uint32_t uCode = (uTestCase * 1000000) +
35 (uTestNumber * 1000) +
36 (uint32_t)uErrorCode;
37 return (int32_t)uCode;
38}
39
40
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -070041#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade9682a532020-06-06 18:33:04 -070042
Laurence Lundbladed711fb22018-09-26 14:35:22 -070043#include "half_to_double_from_rfc7049.h"
Laurence Lundblade68a13352018-09-23 02:19:54 -070044
Laurence Lundblade2d85ce42018-10-12 14:12:47 +080045
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -080046struct FloatTestCase {
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070047 double dNumber;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -080048 float fNumber;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070049 UsefulBufC Preferred;
50 UsefulBufC NotPreferred;
51 UsefulBufC CDE;
52 UsefulBufC DCBOR;
53};
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -070054
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -080055/* Boundaries for destination conversions:
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070056 *
57 * smallest subnormal single 1.401298464324817e-45 2^^-149
58 * largest subnormal single 1.1754942106924411e-38 2^^-126
59 * smallest normal single 1.1754943508222875e-38
60 * largest single 3.4028234663852886E+38
61 *
62 * smallest subnormal half 5.9604644775390625E-8
63 * largest subnormal half 6.097555160522461E-5
64 * smallest normal half 6.103515625E-5
65 * largest half 65504.0
66 *
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -080067 * Boundaries for origin conversions:
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070068 * smallest subnormal double 5.0e-324 2^^-1074
69 * largest subnormal double
70 * smallest normal double 2.2250738585072014e-308 2^^-1022
71 * largest normal double 1.7976931348623157e308 2^^-1023
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -080072 *
73 * Boundaries for double conversion to 64-bit integer:
74 * exponent 51, 52 significand bits set 4503599627370495
75 * exponent 52, 52 significand bits set 9007199254740991
76 * exponent 53, 52 bits set in significand 18014398509481982
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070077 */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070078
79/* Always four lines per test case so shell scripts can process into
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -080080 * other formats. CDE and DCBOR standards are not complete yet,
81 * encodings are what is expected. C string literals are used because they
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070082 * are the shortest notation. They are used __with a length__ . Null
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -080083 * termination doesn't work because there are zero bytes.
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070084 */
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -080085static const struct FloatTestCase FloatTestCases[] = {
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070086 /* Zero */
87 {0.0, 0.0f,
88 {"\xF9\x00\x00", 3}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -080089 {"\xF9\x00\x00", 3}, {"\x00", 1}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070090
91 /* Negative Zero */
92 {-0.0, -0.0f,
93 {"\xF9\x80\x00", 3}, {"\xFB\x80\x00\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -080094 {"\xF9\x80\x00", 3}, {"\x00", 1}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -070095
96 /* NaN */
97 {NAN, NAN,
98 {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9},
99 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
100
101 /* Infinity */
102 {INFINITY, INFINITY,
103 {"\xF9\x7C\x00", 3}, {"\xFB\x7F\xF0\x00\x00\x00\x00\x00\x00", 9},
104 {"\xF9\x7C\x00", 3}, {"\xF9\x7C\x00", 3}},
105
106 /* Negative Infinity */
107 {-INFINITY, -INFINITY,
108 {"\xF9\xFC\x00", 3}, {"\xFB\xFF\xF0\x00\x00\x00\x00\x00\x00", 9},
109 {"\xF9\xFC\x00", 3}, {"\xF9\xFC\x00", 3}},
110
111 /* 1.0 */
112 {1.0, 1.0f,
113 {"\xF9\x3C\x00", 3}, {"\xFB\x3F\xF0\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800114 {"\xF9\x3C\x00", 3}, {"\x01", 1}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700115
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800116 /* -2.0 -- a negative */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700117 {-2.0, -2.0f,
118 {"\xF9\xC0\x00", 3}, {"\xFB\xC0\x00\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800119 {"\xF9\xC0\x00", 3}, {"\x21", 1}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700120
121 /* 1/3 */
122 {0.333251953125, 0.333251953125f,
123 {"\xF9\x35\x55", 3}, {"\xFB\x3F\xD5\x54\x00\x00\x00\x00\x00", 9},
124 {"\xF9\x35\x55", 3}, {"\xF9\x35\x55", 3}},
125
126 /* 5.9604644775390625E-8 -- smallest half-precision subnormal */
127 {5.9604644775390625E-8, 0.0f,
128 {"\xF9\x00\x01", 3}, {"\xFB\x3E\x70\x00\x00\x00\x00\x00\x00", 9},
129 {"\xF9\x00\x01", 3}, {"\xF9\x00\x01", 3}},
130
131 /* 3.0517578125E-5 -- a half-precision subnormal */
132 {3.0517578125E-5, 0.0f,
133 {"\xF9\x02\x00", 3}, {"\xFB\x3F\x00\x00\x00\x00\x00\x00\x00", 9},
134 {"\xF9\x02\x00", 3}, {"\xF9\x02\x00", 3}},
135
136 /* 6.097555160522461E-5 -- largest half-precision subnormal */
137 {6.097555160522461E-5, 0.0f,
138 {"\xF9\x03\xFF", 3}, {"\xFB\x3F\x0F\xF8\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800139 {"\xF9\x03\xFF", 3}, {"\xF9\x03\xFF", 3}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700140
141 /* 6.1035156249999993E-5 -- slightly smaller than smallest half-precision normal */
142 {6.1035156249999993E-5, 0.0f,
143 {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
144 {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x3F\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
145
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800146 /* 6.103515625E-5 -- smallest half-precision normal */
147 {6.103515625E-5, 0.0f,
148 {"\xF9\04\00", 3}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x00", 9},
149 {"\xF9\04\00", 3}, {"\xF9\04\00", 3}},
150
151 /* 6.1035156250000014E-5 -- slightly larger than smallest half-precision normal */
152 {6.1035156250000014E-5, 0.0f,
153 {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9},
154 {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x3F\x10\x00\x00\x00\x00\x00\x01", 9}},
155
156 /* 65504.0 -- largest half-precision */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700157 {65504.0, 0.0f,
158 {"\xF9\x7B\xFF", 3}, {"\xFB\x40\xEF\xFC\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800159 {"\xF9\x7B\xFF", 3}, {"\x19\xFF\xE0", 3}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700160
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800161 /* 65504.1 -- exponent too large and too much precision to convert to half */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700162 {65504.1, 0.0f,
163 {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9},
164 {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}, {"\xFB\x40\xEF\xFC\x03\x33\x33\x33\x33", 9}},
165
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800166 /* 65536.0 -- exponent too large for half but not too much precision for single */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700167 {65536.0, 65536.0f,
168 {"\xFA\x47\x80\x00\x00", 5}, {"\xFB\x40\xF0\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800169 {"\xFA\x47\x80\x00\x00", 5}, {"\x1A\x00\x01\x00\x00", 5}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700170
171 /* 1.401298464324817e-45 -- smallest single subnormal */
172 {1.401298464324817e-45, 1.40129846E-45f,
173 {"\xFA\x00\x00\x00\x01", 5}, {"\xFB\x36\xA0\x00\x00\x00\x00\x00\x00", 9},
174 {"\xFA\x00\x00\x00\x01", 5}, {"\xFA\x00\x00\x00\x01", 5}},
175
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800176 /* 5.8774717541114375E-39 -- slightly smaller than the smallest single normal */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700177 {5.8774717541114375E-39, 5.87747175E-39f,
178 {"\xFA\x00\x40\x00\x00", 5}, {"\xFB\x38\x00\x00\x00\x00\x00\x00\x00", 9},
179 {"\xFA\x00\x40\x00\x00", 5}, {"\xFA\x00\x40\x00\x00", 5}},
180
181 /* 1.1754942106924411e-38 -- largest single subnormal */
182 {1.1754942106924411E-38, 1.17549421E-38f,
183 {"\xFA\x00\x7f\xff\xff", 5}, {"\xFB\x38\x0f\xff\xff\xC0\x00\x00\x00", 9},
184 {"\xFA\x00\x7f\xff\xff", 5}, {"\xFA\x00\x7f\xff\xff", 5} },
185
186 /* 1.1754943508222874E-38 -- slightly bigger than smallest single normal */
187 {1.1754943508222874E-38, 0.0f,
188 {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9},
189 {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}, {"\xFB\x38\x0f\xff\xff\xff\xff\xff\xff", 9}},
190
191 /* 1.1754943508222875e-38 -- smallest single normal */
192 {1.1754943508222875e-38, 1.17549435E-38f,
193 {"\xFA\x00\x80\x00\x00", 5}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x00", 9},
194 {"\xFA\x00\x80\x00\x00", 5}, {"\xFA\x00\x80\x00\x00", 5}},
195
196 /* 1.1754943508222875e-38 -- slightly bigger than smallest single normal */
197 {1.1754943508222878e-38, 0.0f,
198 {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9},
199 {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x38\x10\x00\x00\x00\x00\x00\x01", 9}},
200
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800201 /* 8388607 -- exponent 22 to test single exponent boundary */
202 {8388607, 8388607.0f,
203 {"\xFA\x4A\xFF\xFF\xFE", 5}, {"\xFB\x41\x5F\xFF\xFF\xC0\x00\x00\x00", 9},
204 {"\xFA\x4A\xFF\xFF\xFE", 5}, {"\x1A\x00\x7F\xFF\xFF", 5}},
205
206 /* 16777215 -- exponent 23 to test single exponent boundary */
207 {16777215, 16777215.0f,
208 {"\xFA\x4B\x7F\xFF\xFF", 5}, {"\xFB\x41\x6F\xFF\xFF\xE0\x00\x00\x00", 9},
209 {"\xFA\x4B\x7F\xFF\xFF", 5}, {"\x1A\x00\xFF\xFF\xFF", 5}},
210
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700211 /* 16777216 -- converts to single without loss */
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800212 {16777216, 16777216.0f,
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700213 {"\xFA\x4B\x80\x00\x00", 5}, {"\xFB\x41\x70\x00\x00\x00\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800214 {"\xFA\x4B\x80\x00\x00", 5}, {"\x1A\x01\x00\x00\x00", 5}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700215
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800216 /* 16777217 -- one more than above and fails conversion to single because of precision */
217 {16777217, 0.0f,
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700218 {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800219 {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\x1A\x01\x00\x00\x01", 5}},
220
221 /* 33554430 -- exponent 24 to test single exponent boundary */
222 {33554430, 33554430.0f,
223 {"\xFA\x4B\xFF\xFF\xFF", 5}, {"\xFB\x41\x7F\xFF\xFF\xE0\x00\x00\x00", 9},
224 {"\xFA\x4B\xFF\xFF\xFF", 5}, {"\x1A\x01\xFF\xFF\xFE", 5}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700225
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800226 /* 4294967295 -- 2^^32 - 1 UINT32_MAX */
227 {4294967295, 0,
228 {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9},
229 {"\xFB\x41\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\x1A\xFF\xFF\xFF\xFF", 5}},
230
231 /* 4294967296 -- 2^^32, UINT32_MAX + 1 */
232 {4294967296, 4294967296.0f,
233 {"\xFA\x4F\x80\x00\x00", 5}, {"\xFB\x41\xF0\x00\x00\x00\x00\x00\x00", 9},
234 {"\xFA\x4F\x80\x00\x00", 5}, {"\x1B\x00\x00\x00\x01\x00\x00\x00\x00", 9}},
235
236 /* 2251799813685248 -- exponent 51, 0 significand bits set, to test double exponent boundary */
237 {2251799813685248, 2251799813685248.0f,
238 {"\xFA\x59\x00\x00\x00", 5}, {"\xFB\x43\x20\x00\x00\x00\x00\x00\x00", 9},
239 {"\xFA\x59\x00\x00\x00", 5}, {"\x1B\x00\x08\x00\x00\x00\x00\x00\x00", 9}},
240
241 /* 4503599627370495 -- exponent 51, 52 significand bits set to test double exponent boundary*/
242 {4503599627370495, 0,
243 {"\xFB\x43\x2F\xFF\xFF\xFF\xFF\xFF\xFE", 9}, {"\xFB\x43\x2F\xFF\xFF\xFF\xFF\xFF\xFE", 9},
244 {"\xFB\x43\x2F\xFF\xFF\xFF\xFF\xFF\xFE", 9}, {"\x1B\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
245
246 /* 9007199254740991 -- exponent 52, 52 significand bits set to test double exponent boundary */
247 {9007199254740991, 0,
248 {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
249 {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\x00\x1F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
250
251 /* 18014398509481982 -- exponent 53, 52 bits set in significand (double lacks precision to represent 18014398509481983) */
252 {18014398509481982, 0,
253 {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
254 {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFE", 9}},
255
256 /* 18014398509481984 -- next largest possible double above 18014398509481982 */
257 {18014398509481984, 18014398509481984.0f,
258 {"\xFA\x5A\x80\x00\x00", 5}, {"\xFB\x43\x50\x00\x00\x00\x00\x00\x00", 9},
259 {"\xFA\x5A\x80\x00\x00", 5}, {"\x1B\x00\x40\x00\x00\x00\x00\x00\x00", 9}},
260
261 /* 18446742974197924000.0.0 -- largest single that can convert to uint64 */
262 {18446742974197924000.0, 18446742974197924000.0f,
263 {"\xFA\x5F\x7F\xFF\xFF", 5}, {"\xFB\x43\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
264 {"\xFA\x5F\x7F\xFF\xFF", 5}, {"\x1B\xFF\xFF\xFF\x00\x00\x00\x00\x00", 9}},
265
266 /* 18446744073709550000.0 -- largest double that can convert to uint64, almost UINT64_MAX (18446744073709551615) */
267 {18446744073709550000.0, 0,
268 {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
269 {"\xFB\x43\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\xFF\xFF\xFF\xFF\xFF\xFF\xF8\x00", 9}},
270
271 /* 18446744073709552000.0 -- just too large to convert to uint64, but converts to a single, just over UINT64_MAX */
272 {18446744073709552000.0, 18446744073709552000.0f,
273 {"\xFA\x5F\x80\x00\x00", 5}, {"\xFB\x43\xF0\x00\x00\x00\x00\x00\x00", 9},
274 {"\xFA\x5F\x80\x00\x00", 5}, {"\xFA\x5F\x80\x00\x00", 5}},
275
276 /* -4294967295 -- negative UINT32_MAX */
277 {-4294967295.0, 0,
278 {"\xFB\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\xFB\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", 9},
279 {"\xFB\xC1\xEF\xFF\xFF\xFF\xE0\x00\x00", 9}, {"\x3A\xFF\xFF\xFF\xFE", 5}},
280
281 /* -9223372036854774784.0 -- most negative double that converts to int64 */
282 {-9223372036854774784.0, 0,
283 {"\xFB\xC3\xDF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\xC3\xDF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
284 {"\xFB\xC3\xDF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x3B\x7F\xFF\xFF\xFF\xFF\xFF\xFB\xFF", 9}},
285
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700286 /* -18446742974197923840.0 -- large negative that converts to float, but too large for int64 */
287 {-18446742974197923840.0, -18446742974197923840.0f,
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800288 {"\xFA\xDF\x7F\xFF\xFF", 5}, {"\xFB\xC3\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
Laurence Lundblade14ce2282024-07-24 22:13:35 -0700289 {"\xFA\xDF\x7F\xFF\xFF", 5}, {"\x3B\xFF\xFF\xFE\xFF\xFF\xFF\xFF\xFF", 9}},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800290
291 /* 3.4028234663852886E+38 -- largest possible single */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700292 {3.4028234663852886E+38, 3.40282347E+38f,
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800293 {"\xFA\x7F\x7F\xFF\xFF", 5}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
294 {"\xFA\x7F\x7F\xFF\xFF", 5}, {"\xFA\x7F\x7F\xFF\xFF", 5}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700295
296 /* 3.402823466385289E+38 -- slightly larger than largest possible single */
297 {3.402823466385289E+38, 0.0f,
298 {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9},
299 {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}, {"\xFB\x47\xEF\xFF\xFF\xE0\x00\x00\x01", 9}},
300
301 /* 3.402823669209385e+38 -- exponent larger by one than largest possible single */
302 {3.402823669209385e+38, 0.0f,
303 {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9},
304 {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x47\xF0\x00\x00\x00\x00\x00\x00", 9}},
305
306 /* 5.0e-324 -- smallest double subnormal normal */
307 {5.0e-324, 0.0f,
308 {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9},
309 {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x00\x00\x00\x00\x00\x00\x00\x01", 9}},
310
311 /* 2.2250738585072009E−308 -- largest double subnormal */
312 {2.2250738585072009e-308, 0.0f,
313 {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
314 {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x00\x0F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
315
316 /* 2.2250738585072014e-308 -- smallest double normal */
317 {2.2250738585072014e-308, 0.0f,
318 {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9},
319 {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}, {"\xFB\x00\x10\x00\x00\x00\x00\x00\x00", 9}},
320
321 /* 1.7976931348623157E308 -- largest double normal */
322 {1.7976931348623157e308, 0.0f,
323 {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
324 {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xEF\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
325
Laurence Lundblade534112f2025-02-26 15:12:47 -0700326 /* -18446744073709551616.0 -- largest that encodes into negative uint64 (65-bit neg) */
327 {-18446744073709551616.0, -18446744073709551616.0f,
328 {"\xFA\xDF\x80\x00\x00", 5}, {"\xFB\xC3\xF0\x00\x00\x00\x00\x00\x00", 9},
329 {"\xFA\xDF\x80\x00\x00", 5}, {"\x3B\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
330
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700331 /* List terminator */
332 {0.0, 0.0f, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700333};
334
335
Laurence Lundblade534112f2025-02-26 15:12:47 -0700336/* Can't use the types double and float here because there's no way in C to
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800337 * construct arbitrary payloads for those types.
338 */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700339struct NaNTestCase {
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800340 uint64_t uDouble; /* Converted to double in test */
341 uint32_t uSingle; /* Converted to single in test */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700342 UsefulBufC Preferred;
343 UsefulBufC NotPreferred;
344 UsefulBufC CDE;
345 UsefulBufC DCBOR;
346};
347
348/* Always four lines per test case so shell scripts can process into
349 * other formats. CDE and DCBOR standards are not complete yet,
350 * encodings are a guess. C string literals are used because they
351 * are the shortest notation. They are used __with a length__ . Null
352 * termination doesn't work because there are zero bytes.
353 */
354static const struct NaNTestCase NaNTestCases[] = {
355
356 /* Payload with most significant bit set, a qNaN by most implementations */
357 {0x7ff8000000000000, 0x00000000,
358 {"\xF9\x7E\x00", 3}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9},
359 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
360
361 /* Payload with single rightmost set */
362 {0x7ff8000000000001, 0x00000000,
363 {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x01", 9},
364 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
365
366 /* Payload with 10 leftmost bits set -- converts to half */
367 {0x7ffffc0000000000, 0x00000000,
368 {"\xF9\x7F\xFF", 3}, {"\xFB\x7F\xFF\xFC\x00\x00\x00\x00\x00", 9},
369 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
370
371 /* Payload with 10 rightmost bits set -- cannot convert to half */
372 {0x7ff80000000003ff, 0x00000000,
373 {"\xFB\x7F\xF8\x00\x00\x00\x00\x03\xFF", 9}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x03\xFF", 9},
374 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
375
376 /* Payload with 23 leftmost bits set -- converts to a single */
377 {0x7ffFFFFFE0000000, 0x7fffffff,
378 {"\xFA\x7F\xFF\xFF\xFF", 5}, {"\xFB\x7F\xFF\xFF\xFF\xE0\x00\x00\x00", 9},
379 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
380
381 /* Payload with 24 leftmost bits set -- fails to convert to a single */
382 {0x7ffFFFFFF0000000, 0x00000000,
383 {"\xFB\x7F\xFF\xFF\xFF\xF0\x00\x00\x00", 9}, {"\xFB\x7F\xFF\xFF\xFF\xF0\x00\x00\x00", 9},
384 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
385
386 /* Payload with all bits set */
387 {0x7fffffffffffffff, 0x00000000,
388 {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800389 {"\xF9\x7E\x00", 3}, {"\xF9\x7E\x00", 3}},
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700390
391 /* List terminator */
392 {0, 0, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} }
393};
394
395
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700396/* Public function. See float_tests.h
397 *
398 * This is the main test of floating-point encoding / decoding. It is
399 * data-driven by the above tables. It works better than tests below that
400 * it mostly replaces because it tests one number at a time, rather than
401 * putting them all in a map. It is much easier to debug test failures
402 * and to add new tests. */
403int32_t
404FloatValuesTests(void)
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700405{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700406 unsigned int uTestIndex;
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800407 const struct FloatTestCase *pTestCase;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700408 const struct NaNTestCase *pNaNTestCase;
409 MakeUsefulBufOnStack( TestOutBuffer, 20);
410 UsefulBufC TestOutput;
411 QCBOREncodeContext EnCtx;
412 QCBORError uErr;
413 QCBORDecodeContext DCtx;
414 QCBORItem Item;
415 uint64_t uDecoded;
416#ifdef QCBOR_DISABLE_FLOAT_HW_USE
417 uint32_t uDecoded2;
418#endif
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700419
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700420 /* Test a variety of doubles */
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800421 for(uTestIndex = 0; FloatTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
422 pTestCase = &FloatTestCases[uTestIndex];
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700423
Laurence Lundblade534112f2025-02-26 15:12:47 -0700424 if(uTestIndex == 48) {
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800425 uDecoded = 1;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700426 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800427
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700428 /* Number Encode of Preferred */
429 QCBOREncode_Init(&EnCtx, TestOutBuffer);
430 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
431 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800432
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700433 if(uErr != QCBOR_SUCCESS) {
434 return MakeTestResultCode(uTestIndex, 1, uErr);;
435 }
436 if(UsefulBuf_Compare(TestOutput, pTestCase->Preferred)) {
437 return MakeTestResultCode(uTestIndex, 1, 200);
438 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700439
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700440 /* Number Encode of Not Preferred */
441 QCBOREncode_Init(&EnCtx, TestOutBuffer);
442 QCBOREncode_AddDoubleNoPreferred(&EnCtx, pTestCase->dNumber);
443 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
Laurence Lundblade68a13352018-09-23 02:19:54 -0700444
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700445 if(uErr != QCBOR_SUCCESS) {
446 return MakeTestResultCode(uTestIndex, 2, uErr);;
447 }
448 if(UsefulBuf_Compare(TestOutput, pTestCase->NotPreferred)) {
449 return MakeTestResultCode(uTestIndex, 2, 200);
450 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800451
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800452 /* Number Encode of CDE */
453 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade82634b62024-11-20 22:37:45 -0800454 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_CDE);
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800455 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
456 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
457
458 if(uErr != QCBOR_SUCCESS) {
459 return MakeTestResultCode(uTestIndex, 20, uErr);;
460 }
461 if(UsefulBuf_Compare(TestOutput, pTestCase->CDE)) {
462 return MakeTestResultCode(uTestIndex, 21, 200);
463 }
464
465 /* Number Encode of dCBOR */
466 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade82634b62024-11-20 22:37:45 -0800467 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR);
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800468 QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
469 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
470
471 if(uErr != QCBOR_SUCCESS) {
472 return MakeTestResultCode(uTestIndex, 22, uErr);;
473 }
474 if(UsefulBuf_Compare(TestOutput, pTestCase->DCBOR)) {
475 return MakeTestResultCode(uTestIndex, 23, 200);
476 }
477
478 if(pTestCase->fNumber != 0) {
479 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade82634b62024-11-20 22:37:45 -0800480 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR);
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800481 QCBOREncode_AddFloat(&EnCtx, pTestCase->fNumber);
482 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
483
484 if(uErr != QCBOR_SUCCESS) {
485 return MakeTestResultCode(uTestIndex, 24, uErr);;
486 }
487 if(UsefulBuf_Compare(TestOutput, pTestCase->DCBOR)) {
488 return MakeTestResultCode(uTestIndex, 25, 200);
489 }
490 }
491
492
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700493 /* Number Decode of Preferred */
494 QCBORDecode_Init(&DCtx, pTestCase->Preferred, 0);
495 uErr = QCBORDecode_GetNext(&DCtx, &Item);
496 if(uErr != QCBOR_SUCCESS) {
497 return MakeTestResultCode(uTestIndex, 3, uErr);;
498 }
499#ifndef QCBOR_DISABLE_FLOAT_HW_USE
500 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
501 return MakeTestResultCode(uTestIndex, 4, 0);
502 }
503 if(isnan(pTestCase->dNumber)) {
504 if(!isnan(Item.val.dfnum)) {
505 return MakeTestResultCode(uTestIndex, 5, 0);
506 }
507 } else {
508 if(Item.val.dfnum != pTestCase->dNumber) {
509 return MakeTestResultCode(uTestIndex, 6, 0);
510 }
511 }
512#else /* QCBOR_DISABLE_FLOAT_HW_USE */
513 /* When QCBOR_DISABLE_FLOAT_HW_USE is set, single-precision is not
514 * converted to double when decoding, so test differently. len == 5
515 * indicates single-precision in the encoded CBOR. */
516 if(pTestCase->Preferred.len == 5) {
517 if(Item.uDataType != QCBOR_TYPE_FLOAT) {
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800518 return MakeTestResultCode(uTestIndex, 41, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700519 }
520 if(isnan(pTestCase->dNumber)) {
521 if(!isnan(Item.val.fnum)) {
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800522 return MakeTestResultCode(uTestIndex, 51, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700523 }
524 } else {
525 if(Item.val.fnum != pTestCase->fNumber) {
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800526 return MakeTestResultCode(uTestIndex, 61, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700527 }
528 }
529 } else {
530 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800531 return MakeTestResultCode(uTestIndex, 42, 0);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700532 }
533 if(isnan(pTestCase->dNumber)) {
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700534 if(!isnan(Item.val.dfnum)) {
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800535 return MakeTestResultCode(uTestIndex, 52, 0);
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700536 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700537 } else {
538 if(Item.val.dfnum != pTestCase->dNumber) {
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800539 return MakeTestResultCode(uTestIndex, 62, 0);
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700540 }
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700541 }
542 }
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800543#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700544
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700545 /* Number Decode of Not Preferred */
546 QCBORDecode_Init(&DCtx, pTestCase->NotPreferred, 0);
547 uErr = QCBORDecode_GetNext(&DCtx, &Item);
548 if(uErr != QCBOR_SUCCESS) {
549 return MakeTestResultCode(uTestIndex, 7, uErr);;
550 }
551 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
552 return MakeTestResultCode(uTestIndex, 8, 0);
553 }
554 if(isnan(pTestCase->dNumber)) {
555 if(!isnan(Item.val.dfnum)) {
556 return MakeTestResultCode(uTestIndex, 9, 0);
557 }
558 } else {
559 if(Item.val.dfnum != pTestCase->dNumber) {
560 return MakeTestResultCode(uTestIndex, 10, 0);
561 }
562 }
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700563
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700564 }
565
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700566 /* Test a variety of NaNs with payloads */
567 for(uTestIndex = 0; NaNTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
568 pNaNTestCase = &NaNTestCases[uTestIndex];
569
570
571 if(uTestIndex == 4) {
572 uErr = 99; /* For setting break points for particular tests */
573 }
574
575 /* NaN Encode of Preferred */
576 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade82634b62024-11-20 22:37:45 -0800577 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700578 QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
579 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
580 if(uErr != QCBOR_SUCCESS) {
581 return MakeTestResultCode(uTestIndex+100, 10, uErr);;
582 }
583 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) {
584 return MakeTestResultCode(uTestIndex+100, 10, 200);
585 }
586
587#ifdef QCBOR_COMPARE_TO_HW_NAN_CONVERSION
588 {
589 /* This test is off by default. It's purpose is to check
590 * QCBOR's mask-n-shift implementation against the HW/CPU
591 * instructions that do conversion between double and single.
592 * It is off because it is only used on occasion to verify
593 * QCBOR and because it is suspected that some HW/CPU does
594 * implement this correctly. NaN payloads are an obscure
595 * feature. */
596 float f;
597 double d, d2;
598
599 d = UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uNumber);
600
601 /* Cast the double to a single and then back to a double and
602 * see if they are equal. If so, then the NaN payload doesn't
603 * have any bits that are lost when converting to single and
604 * it can be safely converted.
605 *
606 * This test can't be done for half-precision because it is
607 * not widely supported.
608 */
609 f = (float)d;
610 d2 = (double)f;
611
612 /* The length of encoded doubles is 9, singles 5 and halves
613 * 3. If there are NaN payload bits that can't be converted,
614 * then the length must be 9.
615 */
616 if((uint64_t)d != (uint64_t)d2 && pNaNTestCase->Preferred.len != 9) {
617 /* QCBOR conversion not the same as HW conversion */
618 return MakeTestResultCode(uTestIndex, 9, 200);
619 }
620 }
621#endif /* QCBOR_COMPARE_TO_HW_NAN_CONVERSION */
622
623
624 /* NaN Encode of Not Preferred */
625 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade82634b62024-11-20 22:37:45 -0800626 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700627 QCBOREncode_AddDoubleNoPreferred(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
628 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
629 if(uErr != QCBOR_SUCCESS) {
630 return MakeTestResultCode(uTestIndex+100, 11, uErr);;
631 }
632 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
633 return MakeTestResultCode(uTestIndex+100, 11, 200);
634 }
635
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800636 /* NaN Decode of Not Preferred */
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700637 QCBORDecode_Init(&DCtx, pNaNTestCase->Preferred, 0);
Laurence Lundblade82634b62024-11-20 22:37:45 -0800638 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700639 uErr = QCBORDecode_GetNext(&DCtx, &Item);
640 if(uErr != QCBOR_SUCCESS) {
641 return MakeTestResultCode(uTestIndex+100, 12, uErr);
642 }
643
644#ifndef QCBOR_DISABLE_FLOAT_HW_USE
645
646 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
647 if(uDecoded != pNaNTestCase->uDouble) {
648 return MakeTestResultCode(uTestIndex+100, 12, 200);
649 }
650#else /* QCBOR_DISABLE_FLOAT_HW_USE */
651 if(pNaNTestCase->Preferred.len == 5) {
652 if(Item.uDataType != QCBOR_TYPE_FLOAT) {
653 return MakeTestResultCode(uTestIndex, 4, 0);
654 }
655
656 uDecoded2 = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum);
657
658 if(uDecoded2 != pNaNTestCase->uSingle) {
659 return MakeTestResultCode(uTestIndex, 4, 0);
660 }
661 } else {
662 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
663 return MakeTestResultCode(uTestIndex, 4, 0);
664 }
665 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
666 if(uDecoded != pNaNTestCase->uDouble) {
667 return MakeTestResultCode(uTestIndex+100, 12, 200);
668 }
669 }
670#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
671
672 /* NaN Decode of Not Preferred */
673 QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0);
Laurence Lundblade82634b62024-11-20 22:37:45 -0800674 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700675 uErr = QCBORDecode_GetNext(&DCtx, &Item);
676 if(uErr != QCBOR_SUCCESS) {
677 return MakeTestResultCode(uTestIndex+100, 13, uErr);
678 }
679 uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
680 if(uDecoded != pNaNTestCase->uDouble) {
681 return MakeTestResultCode(uTestIndex+100, 13, 200);
682 }
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800683
684
685 /* NaN Encode of DCBOR */
686 QCBOREncode_Init(&EnCtx, TestOutBuffer);
Laurence Lundblade82634b62024-11-20 22:37:45 -0800687 QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR | QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
Laurence Lundbladeeb3cdef2024-02-17 20:38:55 -0800688 QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
689 uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
690 if(uErr != QCBOR_SUCCESS) {
691 return MakeTestResultCode(uTestIndex+100, 14, uErr);;
692 }
693 if(UsefulBuf_Compare(TestOutput, pNaNTestCase->DCBOR)) {
694 return MakeTestResultCode(uTestIndex+100, 14, 200);
695 }
696
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700697 }
698
699 return 0;
Laurence Lundblade570fab52018-10-13 18:28:27 +0800700}
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700701
702
703
704/* Public function. See float_tests.h */
705int32_t
706HalfPrecisionAgainstRFCCodeTest(void)
707{
708 QCBORItem Item;
709 QCBORDecodeContext DC;
710 unsigned char pbHalfBytes[2];
711 uint8_t uHalfPrecInitialByte;
712 double d;
713 UsefulBuf_MAKE_STACK_UB(EncodedBytes, 3);
714 UsefulOutBuf UOB;
715 uint32_t uHalfP;
716
717
718 for(uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
719 pbHalfBytes[1] = (uint8_t)(uHalfP & 0xff);
720 pbHalfBytes[0] = (uint8_t)(uHalfP >> 8); /* uHalfP is always less than 0xffff */
721 d = decode_half(pbHalfBytes);
722
723 /* Construct the CBOR for the half-precision float by hand */
724 UsefulOutBuf_Init(&UOB, EncodedBytes);
725
726 uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); /* 0xf9 */
727 UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); /* initial byte */
728 UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP); /* argument */
729
730 /* Now parse the hand-constructed CBOR. This will invoke the
731 * conversion to a float
732 */
733 QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
734 QCBORDecode_GetNext(&DC, &Item);
735 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
736 return -1;
737 }
738
739 if(isnan(d)) {
740 /* The RFC code uses the native instructions which may or may not
741 * handle sNaN, qNaN and NaN payloads correctly. This test just
742 * makes sure it is a NaN and doesn't worry about the type of NaN
743 */
744 if(!isnan(Item.val.dfnum)) {
745 return -3;
746 }
747 } else {
748 if(Item.val.dfnum != d) {
749 return -2;
750 }
751 }
752 }
753 return 0;
754}
755
Laurence Lundblade585127a2020-07-15 03:25:24 -0700756#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700757
758
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700759/*
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700760 * Some encoded floating point numbers that are used for both
761 * encode and decode tests.
762 *
763 * [0.0, // Half
764 * 3.14, // Double
765 * 0.0, // Double
766 * NaN, // Double
767 * Infinity, // Double
768 * 0.0, // Half (Duplicate because of use in encode tests)
769 * 3.140000104904175, // Single
770 * 0.0, // Single
771 * NaN, // Single
772 * Infinity, // Single
773 * {100: 0.0, 101: 3.1415926, "euler": 2.718281828459045, 105: 0.0,
774 * 102: 0.0, 103: 3.141592502593994, "euler2": 2.7182817459106445, 106: 0.0}]
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700775 */
776static const uint8_t spExpectedFloats[] = {
777 0x8B,
778 0xF9, 0x00, 0x00,
779 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
780 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
781 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
782 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
783 0xF9, 0x00, 0x00,
784 0xFA, 0x40, 0x48, 0xF5, 0xC3,
785 0xFA, 0x00, 0x00, 0x00, 0x00,
786 0xFA, 0x7F, 0xC0, 0x00, 0x00,
787 0xFA, 0x7F, 0x80, 0x00, 0x00,
788 0xA8,
789 0x18, 0x64,
790 0xF9, 0x00, 0x00,
791 0x18, 0x65,
792 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
793 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
794 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
795 0x18, 0x69,
796 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
797 0x18, 0x66,
798 0xF9, 0x00, 0x00,
799 0x18, 0x67,
800 0xFA, 0x40, 0x49, 0x0F, 0xDA,
801 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
802 0xFA, 0x40, 0x2D, 0xF8, 0x54,
803 0x18, 0x6A,
804 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700805
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200806#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700807static const uint8_t spExpectedFloatsNoHalf[] = {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700808 0x8B,
809 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
811 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
812 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
813 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
814 0xFA, 0x00, 0x00, 0x00, 0x00,
815 0xFA, 0x40, 0x48, 0xF5, 0xC3,
816 0xFA, 0x00, 0x00, 0x00, 0x00,
817 0xFA, 0x7F, 0xC0, 0x00, 0x00,
818 0xFA, 0x7F, 0x80, 0x00, 0x00,
819 0xA8,
820 0x18, 0x64,
821 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
822 0x18, 0x65,
823 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
824 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
825 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
826 0x18, 0x69,
827 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
828 0x18, 0x66,
829 0xFA, 0x00, 0x00, 0x00, 0x00,
830 0x18, 0x67,
831 0xFA, 0x40, 0x49, 0x0F, 0xDA,
832 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
833 0xFA, 0x40, 0x2D, 0xF8, 0x54,
834 0x18, 0x6A,
835 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700836
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700837
838/* Public function. See float_tests.h */
839int32_t
840GeneralFloatEncodeTests(void)
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700841{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700842 /* See FloatNumberTests() for tests that really cover lots of float values.
843 * Add new tests for new values or decode modes there.
844 * This test is primarily to cover all the float encode methods. */
845
846 UsefulBufC Encoded;
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700847 UsefulBufC ExpectedFloats;
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700848 QCBORError uErr;
849
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700850#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700851 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloats));
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700852 ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700853 (void)spExpectedFloatsNoHalf; /* Avoid unused variable error */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700854#else
855 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloatsNoHalf));
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700856 ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloatsNoHalf);
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700857 (void)spExpectedFloats; /* Avoid unused variable error */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700858#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700859
860 QCBOREncodeContext EC;
861 QCBOREncode_Init(&EC, OutBuffer);
862 QCBOREncode_OpenArray(&EC);
863
864 QCBOREncode_AddDouble(&EC, 0.0);
865 QCBOREncode_AddDouble(&EC, 3.14);
866 QCBOREncode_AddDoubleNoPreferred(&EC, 0.0);
867 QCBOREncode_AddDoubleNoPreferred(&EC, NAN);
868 QCBOREncode_AddDoubleNoPreferred(&EC, INFINITY);
869
870 QCBOREncode_AddFloat(&EC, 0.0);
871 QCBOREncode_AddFloat(&EC, 3.14f);
872 QCBOREncode_AddFloatNoPreferred(&EC, 0.0f);
873 QCBOREncode_AddFloatNoPreferred(&EC, NAN);
874 QCBOREncode_AddFloatNoPreferred(&EC, INFINITY);
875
876 QCBOREncode_OpenMap(&EC);
877
878 QCBOREncode_AddDoubleToMapN(&EC, 100, 0.0);
879 QCBOREncode_AddDoubleToMapN(&EC, 101, 3.1415926);
880 QCBOREncode_AddDoubleToMap(&EC, "euler", 2.71828182845904523536);
881 QCBOREncode_AddDoubleNoPreferredToMapN(&EC, 105, 0.0);
882
883 QCBOREncode_AddFloatToMapN(&EC, 102, 0.0f);
884 QCBOREncode_AddFloatToMapN(&EC, 103, 3.1415926f);
885 QCBOREncode_AddFloatToMap(&EC, "euler2", 2.71828182845904523536f);
886 QCBOREncode_AddFloatNoPreferredToMapN(&EC, 106, 0.0f);
887
888 QCBOREncode_CloseMap(&EC);
889 QCBOREncode_CloseArray(&EC);
890
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700891 uErr = QCBOREncode_Finish(&EC, &Encoded);
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700892 if(uErr) {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700893 return -1;
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700894 }
895
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700896 if(UsefulBuf_Compare(Encoded, ExpectedFloats)) {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700897 return -3;
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700898 }
899
900 return 0;
901}
902
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200903#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700904
905
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700906/* Public function. See float_tests.h */
907int32_t
908GeneralFloatDecodeTests(void)
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700909{
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -0700910 /* See FloatNumberTests() for tests that really cover lots of float values */
911
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700912 QCBORItem Item;
913 QCBORError uErr;
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700914 QCBORDecodeContext DC;
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700915
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700916 UsefulBufC TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
917 QCBORDecode_Init(&DC, TestData, 0);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700918
919 QCBORDecode_GetNext(&DC, &Item);
920 if(Item.uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700921 return MakeTestResultCode(0, 1, 0);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700922 }
923
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700924 /* 0.0 half-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700925 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200926 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
927#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
928 || Item.uDataType != QCBOR_TYPE_DOUBLE
929 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700930#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
931 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200932#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
933 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700934 return MakeTestResultCode(0, 2, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700935 }
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700936
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700937 /* 3.14 double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700938 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200939 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
940#ifndef USEFULBUF_DISABLE_ALL_FLOAT
941 || Item.uDataType != QCBOR_TYPE_DOUBLE
942 || Item.val.dfnum != 3.14
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700943#else /* USEFULBUF_DISABLE_ALL_FLOAT */
944 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200945#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
946 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700947 return MakeTestResultCode(0, 3, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700948 }
949
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700950 /* 0.0 double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700951 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200952 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
953#ifndef USEFULBUF_DISABLE_ALL_FLOAT
954 || Item.uDataType != QCBOR_TYPE_DOUBLE
955 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700956#else /* USEFULBUF_DISABLE_ALL_FLOAT */
957 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200958#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
959 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700960 return MakeTestResultCode(0, 4, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700961 }
962
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700963 /* NaN double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700964 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200965 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
966#ifndef USEFULBUF_DISABLE_ALL_FLOAT
967 || Item.uDataType != QCBOR_TYPE_DOUBLE
968 || !isnan(Item.val.dfnum)
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700969#else /* USEFULBUF_DISABLE_ALL_FLOAT */
970 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200971#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
972 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700973 return MakeTestResultCode(0, 5, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700974 }
975
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700976 /* Infinity double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700977 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200978 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
979#ifndef USEFULBUF_DISABLE_ALL_FLOAT
980 || Item.uDataType != QCBOR_TYPE_DOUBLE
981 || Item.val.dfnum != INFINITY
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700982#else /* USEFULBUF_DISABLE_ALL_FLOAT */
983 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200984#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
985 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700986 return MakeTestResultCode(0, 6, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700987 }
988
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700989 /* 0.0 half-precision (again) */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700990 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200991 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
992#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
993 || Item.uDataType != QCBOR_TYPE_DOUBLE
994 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700995#else /* USEFULBUF_DISABLE_ALL_FLOAT */
996 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200997#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
998 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700999 return MakeTestResultCode(0, 7, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001000 }
1001
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001002 /* 3.140000104904175 single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001003 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001004 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1005#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001006#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001007 || Item.uDataType != QCBOR_TYPE_DOUBLE
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001008 || 3.1400001049041748 != Item.val.dfnum
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001009#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001010 || Item.uDataType != QCBOR_TYPE_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001011 || 3.140000f != Item.val.fnum
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001012#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1013#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1014 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001015#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1016 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001017 return MakeTestResultCode(0, 8, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001018 }
1019
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001020 /* 0.0 single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001021 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001022 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1023#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001024#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1025 || Item.uDataType != QCBOR_TYPE_DOUBLE
1026 || Item.val.dfnum != 0.0
1027#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001028 || Item.uDataType != QCBOR_TYPE_FLOAT
Laurence Lundblade83dbf5c2024-01-07 19:17:52 -07001029 || Item.val.fnum != 0.0f
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001030#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1031#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1032 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001033#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1034 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001035 return MakeTestResultCode(0, 9, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001036 }
1037
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001038 /* NaN single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001039 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001040 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1041#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001042#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1043 || Item.uDataType != QCBOR_TYPE_DOUBLE
1044 || !isnan(Item.val.dfnum)
1045#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001046 || Item.uDataType != QCBOR_TYPE_FLOAT
1047 || !isnan(Item.val.fnum)
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001048#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1049#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1050 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001051#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1052 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001053 return MakeTestResultCode(0, 10, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001054 }
1055
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001056 /* Infinity single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001057 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001058 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
1059#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001060#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1061 || Item.uDataType != QCBOR_TYPE_DOUBLE
1062 || Item.val.dfnum != INFINITY
1063#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001064 || Item.uDataType != QCBOR_TYPE_FLOAT
1065 || Item.val.fnum != INFINITY
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001066#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1067#else /* USEFULBUF_DISABLE_ALL_FLOAT */
1068 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001069#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
1070 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001071 return MakeTestResultCode(0, 11, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001072 }
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001073 /* Sufficent test coverage. Don't need to decode the rest. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001074
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001075
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001076#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001077 /* Now tests for spiffy decode main function */
1078 TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001079 double d;
1080 QCBORDecode_Init(&DC, TestData, 0);
Laurence Lundblade6545d1b2020-10-14 11:13:13 -07001081 QCBORDecode_EnterArray(&DC, NULL);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001082
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001083 /* 0.0 half-precision */
1084 QCBORDecode_GetDouble(&DC, &d);
1085 uErr = QCBORDecode_GetAndResetError(&DC);
1086 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001087#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001088 || d != 0.0
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001089#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -07001090 ) {
1091 return MakeTestResultCode(1, 1, uErr);
1092 }
1093
1094 /* 3.14 double-precision */
1095 QCBORDecode_GetDouble(&DC, &d);
1096 uErr = QCBORDecode_GetAndResetError(&DC);
1097 if(uErr != QCBOR_SUCCESS || d != 3.14) {
1098 return MakeTestResultCode(1, 2, uErr);
1099 }
1100
1101 /* 0.0 double-precision */
1102 QCBORDecode_GetDouble(&DC, &d);
1103 uErr = QCBORDecode_GetAndResetError(&DC);
1104 if(uErr != QCBOR_SUCCESS || d != 0.0) {
1105 return MakeTestResultCode(1, 3, uErr);
1106 }
1107
1108 /* NaN double-precision */
1109 QCBORDecode_GetDouble(&DC, &d);
1110 uErr = QCBORDecode_GetAndResetError(&DC);
1111 if(uErr != QCBOR_SUCCESS || !isnan(d)) {
1112 return MakeTestResultCode(1, 4, uErr);
1113 }
1114
1115 /* Infinity double-precision */
1116 QCBORDecode_GetDouble(&DC, &d);
1117 uErr = QCBORDecode_GetAndResetError(&DC);
1118 if(uErr != QCBOR_SUCCESS || d != INFINITY) {
1119 return MakeTestResultCode(1, 5, uErr);
1120 }
1121
1122 /* 0.0 half-precision */
1123 QCBORDecode_GetDouble(&DC, &d);
1124 uErr = QCBORDecode_GetAndResetError(&DC);
1125 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
1126#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
1127 || d != 0.0
1128#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
1129 ) {
1130 return MakeTestResultCode(1, 6, uErr);
1131 }
1132
1133 /* 3.140000104904175 single-precision */
1134 QCBORDecode_GetDouble(&DC, &d);
1135 uErr = QCBORDecode_GetAndResetError(&DC);
1136 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1137#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1138 || d != 3.140000104904175
1139#endif
1140 ) {
1141 return MakeTestResultCode(1, 7, uErr);
1142 }
1143
1144 /* 0.0 single-precision */
1145 QCBORDecode_GetDouble(&DC, &d);
1146 uErr = QCBORDecode_GetAndResetError(&DC);
1147 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1148#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1149 || d != 0.0
1150#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1151 ) {
1152 return MakeTestResultCode(1, 8, uErr);
1153 }
1154
1155 /* NaN single-precision */
1156 QCBORDecode_GetDouble(&DC, &d);
1157 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1158#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1159 || !isnan(d)
1160#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1161 ) {
1162 return MakeTestResultCode(1, 9, uErr);
1163 }
1164
1165 /* Infinity single-precision */
1166 QCBORDecode_GetDouble(&DC, &d);
1167 uErr = QCBORDecode_GetAndResetError(&DC);
1168 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1169#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1170 || d != INFINITY
1171#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1172 ) {
1173 return MakeTestResultCode(1, 10, uErr);
1174 }
1175
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001176#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001177
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001178 return 0;
1179}
1180
1181
Laurence Lundbladed711fb22018-09-26 14:35:22 -07001182
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001183#ifdef NAN_EXPERIMENT
1184/*
1185 Code for checking what the double to float cast does with
1186 NaNs. Not run as part of tests. Keep it around to
1187 be able to check various platforms and CPUs.
1188 */
1189
1190#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
1191#define DOUBLE_NUM_EXPONENT_BITS (11)
1192#define DOUBLE_NUM_SIGN_BITS (1)
1193
1194#define DOUBLE_SIGNIFICAND_SHIFT (0)
1195#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS)
1196#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
1197
1198#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits
1199#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
1200#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
1201#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
1202
1203
1204static int NaNExperiments() {
1205 double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
1206 double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
1207 double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001208
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001209 float f1 = (float)dqNaN;
1210 float f2 = (float)dsNaN;
1211 float f3 = (float)dqNaNPayload;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001212
1213
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001214 uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
1215 uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
1216 uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001217
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001218 // Result of this on x86 is that every NaN is a qNaN. The intel
1219 // CVTSD2SS instruction ignores the NaN payload and even converts
1220 // a sNaN to a qNaN.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001221
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001222 return 0;
1223}
Laurence Lundbladee2c893c2020-12-26 17:41:53 -08001224#endif /* NAN_EXPERIMENT */