blob: a859d1bea9e658866403978d76d7317e2912b9f0 [file] [log] [blame]
Laurence Lundblade68a13352018-09-23 02:19:54 -07001/*==============================================================================
Laurence Lundblade2d85ce42018-10-12 14:12:47 +08002 float_tests.c -- tests for float and conversion to/from half-precision
Laurence Lundblade781fd822018-10-01 09:37:52 -07003
Laurence Lundbladeee851742020-01-08 08:37:05 -08004 Copyright (c) 2018-2020, Laurence Lundblade. All rights reserved.
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02005 Copyright (c) 2021, Arm Limited. All rights reserved.
Laurence Lundblade035bd782019-01-21 17:01:31 -08006
Laurence Lundbladea3fd49f2019-01-21 10:16:22 -08007 SPDX-License-Identifier: BSD-3-Clause
Laurence Lundblade035bd782019-01-21 17:01:31 -08008
Laurence Lundbladea3fd49f2019-01-21 10:16:22 -08009 See BSD-3-Clause license in README.md
Laurence Lundblade035bd782019-01-21 17:01:31 -080010
Laurence Lundbladea3fd49f2019-01-21 10:16:22 -080011 Created on 9/19/18
Laurence Lundbladeee851742020-01-08 08:37:05 -080012 =============================================================================*/
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 Lundblade585127a2020-07-15 03:25:24 -070019#include <math.h> // For INFINITY and NAN and isnan()
20
Laurence Lundblade16a207a2021-09-18 17:22:46 -070021
22/* Make a test results code that includes three components
23 * Return code is
24 * xxxyyyzzz where zz is the error code, yy is the test number and zz is
25 * check being performed
26 */
27static inline int32_t MakeTestResultCode(uint32_t uTestCase,
28 uint32_t uTestNumber,
29 QCBORError uErrorCode)
30{
31 uint32_t uCode = (uTestCase * 1000000) +
32 (uTestNumber * 1000) +
33 (uint32_t)uErrorCode;
34 return (int32_t)uCode;
35}
36
37
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -070038#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade9682a532020-06-06 18:33:04 -070039
Laurence Lundbladed711fb22018-09-26 14:35:22 -070040#include "half_to_double_from_rfc7049.h"
Laurence Lundblade68a13352018-09-23 02:19:54 -070041
Laurence Lundblade2d85ce42018-10-12 14:12:47 +080042
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070043/*
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -070044 Half-precision values that are input to test half-precision decoding
45
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070046 As decoded by http://cbor.me
47 {"zero": 0.0,
48 "infinitity": Infinity,
49 "negative infinitity": -Infinity,
50 "NaN": NaN,
51 "one": 1.0,
52 "one third": 0.333251953125,
53 "largest half-precision": 65504.0,
54 "too-large half-precision": Infinity,
55 "smallest subnormal": 5.960464477539063e-8,
56 "smallest normal": 0.00006097555160522461,
57 "biggest subnormal": 0.00006103515625,
58 "subnormal single": 0.0,
59 3: -2.0,
60 4: NaN,
61 5: NaN,
62 6: NaN,
63 7: NaN}
64 */
Laurence Lundbladebb474be2018-10-22 11:53:21 +053065static const uint8_t spExpectedHalf[] = {
Laurence Lundblade7d40d812018-09-30 02:44:01 -070066 0xB1,
Laurence Lundblade68a13352018-09-23 02:19:54 -070067 0x64,
68 0x7A, 0x65, 0x72, 0x6F,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070069 0xF9, 0x00, 0x00, // half-precision 0.000
Laurence Lundblade68a13352018-09-23 02:19:54 -070070 0x6A,
71 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070072 0xF9, 0x7C, 0x00, // Infinity
Laurence Lundblade68a13352018-09-23 02:19:54 -070073 0x73,
Laurence Lundbladeee851742020-01-08 08:37:05 -080074 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E,
75 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070076 0xF9, 0xFC, 0x00, // -Inifinity
Laurence Lundblade68a13352018-09-23 02:19:54 -070077 0x63,
78 0x4E, 0x61, 0x4E,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070079 0xF9, 0x7E, 0x00, // NaN
Laurence Lundblade68a13352018-09-23 02:19:54 -070080 0x63,
81 0x6F, 0x6E, 0x65,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070082 0xF9, 0x3C, 0x00, // 1.0
Laurence Lundblade68a13352018-09-23 02:19:54 -070083 0x69,
84 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070085 0xF9, 0x35, 0x55, // half-precsion one third 0.333251953125
Laurence Lundblade68a13352018-09-23 02:19:54 -070086 0x76,
Laurence Lundbladeee851742020-01-08 08:37:05 -080087 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C,
88 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070089 0xF9, 0x7B, 0xFF, // largest half-precision 65504.0
Laurence Lundbladeee851742020-01-08 08:37:05 -080090 0x78, 0x18,
91 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x68,
92 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69,
93 0x6F, 0x6E,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070094 0xF9, 0x7C, 0x00, // Infinity
Laurence Lundblade68a13352018-09-23 02:19:54 -070095 0x72,
Laurence Lundbladeee851742020-01-08 08:37:05 -080096 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75,
97 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070098 0xF9, 0x00, 0x01, // Smallest half-precision subnormal 0.000000059604645
Laurence Lundblade68a13352018-09-23 02:19:54 -070099 0x71,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800100 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62,
101 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700102 0xF9, 0x03, 0xFF, // Largest half-precision subnormal 0.0000609755516
103 0x6F,
104 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F,
105 0x72, 0x6D, 0x61, 0x6C,
106 0xF9, 0x04, 0x00, // Smallest half-precision normal 0.000061988
Laurence Lundblade68a13352018-09-23 02:19:54 -0700107 0x70,
Laurence Lundbladeee851742020-01-08 08:37:05 -0800108 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73,
109 0x69, 0x6E, 0x67, 0x6C, 0x65,
Laurence Lundblade68a13352018-09-23 02:19:54 -0700110 0xF9, 0x00, 0x00,
111 0x03,
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700112 0xF9, 0xC0, 0x00, // -2
113 0x04,
114 0xF9, 0x7E, 0x00, // qNaN
115 0x05,
116 0xF9, 0x7C, 0x01, // sNaN
117 0x06,
118 0xF9, 0x7E, 0x0F, // qNaN with payload 0x0f
119 0x07,
120 0xF9, 0x7C, 0x0F, // sNaN with payload 0x0f
Laurence Lundblade68a13352018-09-23 02:19:54 -0700121};
122
123
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700124inline static bool CheckDouble(double d, uint64_t u)
125{
126 return UsefulBufUtil_CopyDoubleToUint64(d) != u;
127}
128
129
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300130int32_t HalfPrecisionDecodeBasicTests(void)
Laurence Lundblade68a13352018-09-23 02:19:54 -0700131{
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700132 UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800133
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700134 QCBORDecodeContext DC;
135 QCBORDecode_Init(&DC, HalfPrecision, 0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800136
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700137 QCBORItem Item;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700138
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700139 QCBORDecode_GetNext(&DC, &Item);
140 if(Item.uDataType != QCBOR_TYPE_MAP) {
141 return -1;
142 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700143
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700144 QCBORDecode_GetNext(&DC, &Item);
145 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0) {
146 return -2;
147 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800148
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700149 QCBORDecode_GetNext(&DC, &Item);
150 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
151 return -3;
152 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700153
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700154 QCBORDecode_GetNext(&DC, &Item);
155 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -INFINITY) {
156 return -4;
157 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700158
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700159 // TODO: NAN-related is this really converting right? It is carrying
160 // payload, but this confuses things.
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700161 QCBORDecode_GetNext(&DC, &Item);
162 if(Item.uDataType != QCBOR_TYPE_DOUBLE || !isnan(Item.val.dfnum)) {
163 return -5;
164 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700165
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700166 QCBORDecode_GetNext(&DC, &Item);
167 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 1.0) {
168 return -6;
169 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800170
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700171 // Approximately 1/3
172 QCBORDecode_GetNext(&DC, &Item);
173 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.333251953125) {
174 return -7;
175 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700176
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700177 // Largest half-precision
178 QCBORDecode_GetNext(&DC, &Item);
179 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 65504.0) {
180 return -8;
181 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700182
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700183 QCBORDecode_GetNext(&DC, &Item);
184 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
185 return -9;
186 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800187
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700188 // Smallest half-precision subnormal
189 QCBORDecode_GetNext(&DC, &Item);
190 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00000005960464477539063) {
191 return -10;
192 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700193
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700194 // Largest half-precision subnormal
195 QCBORDecode_GetNext(&DC, &Item);
196 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00006097555160522461) {
197 return -11;
198 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700199
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700200 // Smallest half-precision normal
201 QCBORDecode_GetNext(&DC, &Item);
202 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00006103515625) {
203 return -12;
204 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800205
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700206 // half-precision zero
207 QCBORDecode_GetNext(&DC, &Item);
208 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0) {
209 return -13;
210 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800211
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700212 // negative 2
213 QCBORDecode_GetNext(&DC, &Item);
214 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -2.0) {
215 return -14;
216 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800217
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700218 // TODO: NAN-related double check these four tests
219 QCBORDecode_GetNext(&DC, &Item); // qNaN
220 if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700221 CheckDouble(Item.val.dfnum, 0x7ff8000000000000ULL)) {
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700222 return -15;
223 }
224 QCBORDecode_GetNext(&DC, &Item); // sNaN
225 if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700226 CheckDouble(Item.val.dfnum, 0x7ff0000000000001ULL)) {
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700227 return -16;
228 }
229 QCBORDecode_GetNext(&DC, &Item); // qNaN with payload 0x0f
230 if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700231 CheckDouble(Item.val.dfnum, 0x7ff800000000000fULL)) {
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700232 return -17;
233 }
234 QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f
235 if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700236 CheckDouble(Item.val.dfnum, 0x7ff000000000000fULL)) {
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700237 return -18;
238 }
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700239
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700240 if(QCBORDecode_Finish(&DC)) {
241 return -19;
242 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800243
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700244 return 0;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700245}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700246
247
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700248
249
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300250int32_t HalfPrecisionAgainstRFCCodeTest(void)
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700251{
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700252 for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700253 unsigned char x[2];
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800254 x[1] = (uint8_t)(uHalfP & 0xff);
255 x[0] = (uint8_t)(uHalfP >> 8); // uHalfP is always less than 0xffff
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700256 double d = decode_half(x);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800257
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700258 // Contruct the CBOR for the half-precision float by hand
Laurence Lundblade4fe9f312018-10-22 10:22:39 +0530259 UsefulBuf_MAKE_STACK_UB(__xx, 3);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700260 UsefulOutBuf UOB;
261 UsefulOutBuf_Init(&UOB, __xx);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800262
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800263 const uint8_t uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); // 0xf9
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700264 UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float
265 UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP);
266
Laurence Lundbladeee851742020-01-08 08:37:05 -0800267 // Now parse the hand-constructed CBOR. This will invoke the
268 // conversion to a float
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700269 QCBORDecodeContext DC;
270 QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800271
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700272 QCBORItem Item;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800273
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700274 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700275 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700276 return -1;
277 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800278
Laurence Lundbladeee851742020-01-08 08:37:05 -0800279 //printf("%04x QCBOR:%15.15f RFC: %15.15f (%8x)\n",
280 // uHalfP, Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800281
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700282 if(isnan(d)) {
283 // The RFC code uses the native instructions which may or may not
284 // handle sNaN, qNaN and NaN payloads correctly. This test just
285 // makes sure it is a NaN and doesn't worry about the type of NaN
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700286 if(!isnan(Item.val.dfnum)) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700287 return -3;
288 }
289 } else {
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700290 if(Item.val.dfnum != d) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700291 return -2;
292 }
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700293 }
294 }
295 return 0;
296}
297
298
299/*
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700300 Expected output from preferred serialization of some of floating-point numbers
301{"zero": 0.0,
302 "negative zero": -0.0,
303 "infinitity": Infinity,
304 "negative infinitity": -Infinity,
305 "NaN": NaN,
306 "one": 1.0,
307 "one third": 0.333251953125,
308 "largest half-precision": 65504.0,
309 "largest half-precision point one": 65504.1,
310 "too-large half-precision": 65536.0,
311 "smallest half subnormal": 5.960464477539063e-8,
312 "smallest half normal": 0.00006103515625,
313 "smallest half normal plus": 0.00006103515625000001,
314 "smallest normal minus": 0.000030517578125,
315 "largest single": 3.4028234663852886e+38,
316 "largest single plus": 6.805646932770577e+38,
317 "smallest single": 1.1754943508222875e-38,
318 "smallest single plus": 1.1754943508222878e-38,
319 "smallest single minus": 1.1754943508222874e-38,
320 "smallest single minus more": 5.877471754111438e-39,
321 3: -2.0, "single precision": 16777216.0,
322 "single with precision loss": 16777217.0,
323 1: "fin"}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700324 */
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530325static const uint8_t spExpectedSmallest[] = {
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700326 0xB8, 0x1A,
327 0x64, 0x7A, 0x65, 0x72, 0x6F,
328 0xF9, 0x00, 0x00,
329
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700330 0x6D, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x7A,
331 0x65, 0x72, 0x6F,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700332 0xF9, 0x80, 0x00,
333
334 0x6A, 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
335 0xF9, 0x7C, 0x00,
336
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700337 0x73, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69,
338 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700339 0xF9, 0xFC, 0x00,
340
341 0x63, 0x4E, 0x61, 0x4E,
342 0xF9, 0x7E, 0x00,
343
344 0x63, 0x6F, 0x6E, 0x65,
345 0xF9, 0x3C, 0x00,
346
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700347 0x69, 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700348 0xF9, 0x35, 0x55,
349
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700350 0x76, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61,
351 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69,
352 0x6F, 0x6E,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700353 0xF9, 0x7B, 0xFF,
354
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700355 0x78, 0x20, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68,
356 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73,
357 0x69, 0x6F, 0x6E, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20,
358 0x6F, 0x6E, 0x65,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700359 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33,
360
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700361 0x78, 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65,
362 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63,
363 0x69, 0x73, 0x69, 0x6F, 0x6E,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700364 0xFA, 0x47, 0x80, 0x00, 0x00,
365
366 0x77, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74,
367 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, 0x73, 0x75, 0x62, 0x6E,
368 0x6F, 0x72, 0x6D, 0x61, 0x6C,
369 0xFA, 0x33, 0x80, 0x00, 0x00,
370
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700371 0x74, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x68,
372 0x61, 0x6C, 0x66, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700373 0xF9, 0x04, 0x00,
374
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700375 0x78, 0x19, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20,
376 0x68, 0x61, 0x6C, 0x66, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61,
377 0x6C, 0x20, 0x70, 0x6C, 0x75, 0x73,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700378 0xFB, 0x3F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
379
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700380 0x75, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E,
381 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x6D, 0x69, 0x6E,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700382 0x75, 0x73,
383 0xFB, 0x3F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
384
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700385 0x75, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E,
386 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x6D, 0x69, 0x6E, 0x75,
387 0x73,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700388 0xFA, 0x38, 0x00, 0x00, 0x00,
389
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700390 0x6E, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69,
391 0x6E, 0x67, 0x6C, 0x65,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700392 0xFA, 0x7F, 0x7F, 0xFF, 0xFF,
393
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700394 0x73, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69,
395 0x6E,0x67, 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x75, 0x73,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700396 0xFB, 0x47, 0xEF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01,
397
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700398 0x73, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69,
399 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x75, 0x73,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700400 0xFB, 0x47, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00,
401
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700402 0x6F, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73,
403 0x69, 0x6E, 0x67, 0x6C, 0x65,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700404 0xFA, 0x00, 0x80, 0x00, 0x00,
405
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700406 0x74, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73,
407 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x75, 0x73,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700408 0xFB, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
409
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700410 0x75, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73,
411 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x6D, 0x69, 0x6E, 0x75,
412 0x73,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700413 0xFB, 0x38, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
414
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700415 0x78, 0x1A, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20,
416 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x6D, 0x69, 0x6E,
417 0x75, 0x73, 0x20, 0x6D, 0x6F, 0x72, 0x65,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700418 0xFB, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
419
420 0x03,
421 0xF9, 0xC0, 0x00,
422
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700423 0x70, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x70, 0x72, 0x65,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700424 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
425 0xFA, 0x4B, 0x80, 0x00, 0x00,
426
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700427 0x78, 0x1A, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, 0x69,
428 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69,
429 0x6F, 0x6E, 0x20, 0x6C, 0x6F, 0x73, 0x73,
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700430 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
431
432 0x01,
433 0x63, 0x66, 0x69, 0x6E
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700434};
435
436
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700437/*
438 Makes a double from a uint64_t by copying the bits, not
439 by converting the value.
440 */
441#define MAKE_DOUBLE(x) UsefulBufUtil_CopyUint64ToDouble(x)
442
443
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300444int32_t DoubleAsSmallestTest(void)
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700445{
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700446 UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, sizeof(spExpectedSmallest));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800447
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700448 QCBOREncodeContext EC;
449 QCBOREncode_Init(&EC, EncodedHalfsMem);
450 QCBOREncode_OpenMap(&EC);
Laurence Lundblade067035b2018-11-28 17:35:25 -0800451
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700452 // Many of these are from
453 // https://en.wikipedia.org/wiki/Half-precision_floating-point_format
454 // and
455 // https://en.wikipedia.org/wiki/Single-precision_floating-point_format
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800456
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700457 // F9 0000 # primitive(0)
458 QCBOREncode_AddDoubleToMap(&EC, "zero", 0.00);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700459
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700460 // F9 8000 # primitive(0)
461 QCBOREncode_AddDoubleToMap(&EC, "negative zero", -0.00);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800462
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700463 // F9 7C00 # primitive(31744)
464 QCBOREncode_AddDoubleToMap(&EC, "infinitity", INFINITY);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800465
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700466 // F9 FC00 # primitive(64512)
467 QCBOREncode_AddDoubleToMap(&EC, "negative infinitity", -INFINITY);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800468
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700469 // F9 7E00 # primitive(32256)
470 QCBOREncode_AddDoubleToMap(&EC, "NaN", NAN);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800471
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700472 // TODO: test a few NaN variants
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800473
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700474 // F9 3C00 # primitive(15360)
475 QCBOREncode_AddDoubleToMap(&EC, "one", 1.0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800476
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700477 // F9 3555 # primitive(13653)
478 QCBOREncode_AddDoubleToMap(&EC, "one third", 0.333251953125);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800479
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700480 // 65504.0, converts to the large possible half-precision.
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700481 // 0xF9, 0x7B, 0xFF,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700482 QCBOREncode_AddDoubleToMap(&EC, "largest half-precision", 65504.0);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700483
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700484 // 65504.1, the double that has both to large an exponent and too
485 // much precision, so no conversion.
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700486 // 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700487 QCBOREncode_AddDoubleToMap(&EC, "largest half-precision point one", 65504.1);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800488
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700489 // 65536.0 has an exponent of 16, which is larger than 15, the
490 // largest half-precision exponent. It is the exponent, not
491 // precision loss that prevents conversion to half. It does convert
492 // to single precision.
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700493 // 0xFA, 0x47, 0x80, 0x00, 0x00,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700494 QCBOREncode_AddDoubleToMap(&EC, "too-large half-precision", 65536.0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800495
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700496 // 5.9604644775390625E-8, the smallest possible half-precision
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700497 // subnormal, digitis are lost converting to half, but not
498 // when converting to a single
499 // 0xFA, 0x33, 0x80, 0x00, 0x00,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700500 QCBOREncode_AddDoubleToMap(&EC,
501 "smallest half subnormal",
502 MAKE_DOUBLE(0x3e70000000000000));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800503
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700504 // 0.00006103515625, the double value that converts to the smallest
505 // possible half-precision normal. which is what should appear in
506 // the output.
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700507 // 0xF9, 0x04, 0x00,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700508 QCBOREncode_AddDoubleToMap(&EC,
509 "smallest half normal",
510 MAKE_DOUBLE(0x3f10000000000000));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800511
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700512 // 0.000061035156250000014 ,the double value that is a tiny bit
513 // greater than smallest possible half-precision normal. It will be
514 // output as a double because converting it will reduce precision.
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700515 // 0xFB, 0x3F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700516 QCBOREncode_AddDoubleToMap(&EC,
517 "smallest half normal plus",
518 MAKE_DOUBLE(0x3f10000000000001));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800519
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700520 // 0.000061035156249999993, the double value that is a tiny bit
521 // smaller than the smallest half-precision normal. This will fail
522 // to convert to a half-precision because both the exponent is too
523 // small and the precision is too large for a half-precision.
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700524 // 0xFB, 0x3F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700525 QCBOREncode_AddDoubleToMap(&EC,
526 "smallest normal minus",
527 MAKE_DOUBLE(0x3f0fffffffffffff));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800528
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700529 // 0.000030517578125, the double value that is too small to fit
530 // into a half-precision because the exponent won't fit, not
531 // because precision would be lost. (This would fit into a
532 // half-precision subnormal, but there is no converstion to
533 // that). This ends up encoded as a single-precision.
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700534 // 0xFA, 0x38, 0x00, 0x00, 0x00,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700535 QCBOREncode_AddDoubleToMap(&EC,
536 "smallest normal minus",
537 MAKE_DOUBLE(0x3f00000000000000));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800538
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700539 // 3.4028234664e38, the value that converts to the largest possible
540 // single-precision.
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700541 // 0xFA, 0x7F, 0x7F, 0xFF, 0xFF,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700542 QCBOREncode_AddDoubleToMap(&EC,
543 "largest single",
544 MAKE_DOUBLE(0x47efffffe0000000));
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700545
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700546 // 3.402823466385289E38, sightly larger than the largest possible
547 // possible precision. Conversion fails because precision would be
548 // lost.
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700549 // 0xFB, 0x47, 0xEF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700550 QCBOREncode_AddDoubleToMap(&EC,
551 "largest single plus",
552 MAKE_DOUBLE(0x47efffffe0000001));
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700553
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700554 // 6.8056469327705772E38, slightly more larger than the largers
555 // possible single precision. Conversion fails because exponent is
556 // too large.
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700557 // 0xFB, 0x47, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700558 QCBOREncode_AddDoubleToMap(&EC,
559 "largest single plus",
560 MAKE_DOUBLE(0x47ffffffe0000000));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800561
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700562 // 1.1754943508222875E-38, The double value that converts to the
563 // smallest possible single-precision normal
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700564 // 0xFA, 0x00, 0x80, 0x00, 0x00,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700565 QCBOREncode_AddDoubleToMap(&EC,
566 "smallest single",
567 MAKE_DOUBLE(0x3810000000000000));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800568
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700569 // 1.1754943508222878E-38, double value that is slightly larger
570 // than the smallest single-precision normal. Conversion fails
571 // because of precision
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700572 // 0xFB, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700573 QCBOREncode_AddDoubleToMap(&EC,
574 "smallest single plus",
575 MAKE_DOUBLE(0x3810000000000001));
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700576
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700577 // 1.1754943508222874E-38, slightly smaller than the smallest
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700578 // single-precision normal. Conversion fails because of precision
Laurence Lundblade29ec4642020-07-21 21:11:45 -0700579 // 0xFB, 0x38, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700580 QCBOREncode_AddDoubleToMap(&EC,
581 "smallest single minus",
582 MAKE_DOUBLE(0x380fffffffffffff));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800583
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700584 // 5.8774717541114375E-39, slightly smaller than the smallest
585 // single-precision normal. Conversion fails because the exponent
586 // is too small.
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700587 // 0xFB, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700588 QCBOREncode_AddDoubleToMap(&EC,
589 "smallest single minus more",
590 MAKE_DOUBLE(0x3800000000000000));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800591
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700592 // Just -2, which converts to a negative half-precision
593 // F9 C000 # primitive(49152)
594 QCBOREncode_AddDoubleToMapN(&EC, 3, -2.0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800595
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700596 // 16777216, No precision loss converting to single
597 // FA 4B800000 # primitive(1266679808)
598 QCBOREncode_AddDoubleToMap(&EC, "single precision", 16777216);
599
600 // 16777217, One more than above. Too much precision for a single
601 // so no conversion.
Laurence Lundblade60f30e72020-07-21 11:16:01 -0700602 // 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700603 QCBOREncode_AddDoubleToMap(&EC, "single with precision loss", 16777217);
604
605 // Just a convenient marker when cutting and pasting encoded CBOR
606 QCBOREncode_AddSZStringToMapN(&EC, 1, "fin");
607
608 QCBOREncode_CloseMap(&EC);
609
610 UsefulBufC EncodedHalfs;
611 QCBORError uErr = QCBOREncode_Finish(&EC, &EncodedHalfs);
612 if(uErr) {
613 return -1;
614 }
615
616 if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) {
617 return -3;
618 }
619
620 return 0;
Laurence Lundblade570fab52018-10-13 18:28:27 +0800621}
Laurence Lundblade585127a2020-07-15 03:25:24 -0700622#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700623
624
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700625/*
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700626 * Some encoded floating point numbers that are used for both
627 * encode and decode tests.
628 *
629 * [0.0, // Half
630 * 3.14, // Double
631 * 0.0, // Double
632 * NaN, // Double
633 * Infinity, // Double
634 * 0.0, // Half (Duplicate because of use in encode tests)
635 * 3.140000104904175, // Single
636 * 0.0, // Single
637 * NaN, // Single
638 * Infinity, // Single
639 * {100: 0.0, 101: 3.1415926, "euler": 2.718281828459045, 105: 0.0,
640 * 102: 0.0, 103: 3.141592502593994, "euler2": 2.7182817459106445, 106: 0.0}]
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700641 */
642static const uint8_t spExpectedFloats[] = {
643 0x8B,
644 0xF9, 0x00, 0x00,
645 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
646 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
647 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
648 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
649 0xF9, 0x00, 0x00,
650 0xFA, 0x40, 0x48, 0xF5, 0xC3,
651 0xFA, 0x00, 0x00, 0x00, 0x00,
652 0xFA, 0x7F, 0xC0, 0x00, 0x00,
653 0xFA, 0x7F, 0x80, 0x00, 0x00,
654 0xA8,
655 0x18, 0x64,
656 0xF9, 0x00, 0x00,
657 0x18, 0x65,
658 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
659 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
660 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
661 0x18, 0x69,
662 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
663 0x18, 0x66,
664 0xF9, 0x00, 0x00,
665 0x18, 0x67,
666 0xFA, 0x40, 0x49, 0x0F, 0xDA,
667 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
668 0xFA, 0x40, 0x2D, 0xF8, 0x54,
669 0x18, 0x6A,
670 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700671
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200672#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700673static const uint8_t spExpectedFloatsNoHalf[] = {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700674 0x8B,
675 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
676 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
677 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
678 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
679 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
680 0xFA, 0x00, 0x00, 0x00, 0x00,
681 0xFA, 0x40, 0x48, 0xF5, 0xC3,
682 0xFA, 0x00, 0x00, 0x00, 0x00,
683 0xFA, 0x7F, 0xC0, 0x00, 0x00,
684 0xFA, 0x7F, 0x80, 0x00, 0x00,
685 0xA8,
686 0x18, 0x64,
687 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
688 0x18, 0x65,
689 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
690 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
691 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
692 0x18, 0x69,
693 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
694 0x18, 0x66,
695 0xFA, 0x00, 0x00, 0x00, 0x00,
696 0x18, 0x67,
697 0xFA, 0x40, 0x49, 0x0F, 0xDA,
698 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
699 0xFA, 0x40, 0x2D, 0xF8, 0x54,
700 0x18, 0x6A,
701 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700702
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300703int32_t GeneralFloatEncodeTests(void)
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700704{
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700705 UsefulBufC ExpectedFloats;
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700706#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700707 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloats));
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700708 ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700709 (void)spExpectedFloatsNoHalf; // Avoid unused variable error
710#else
711 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloatsNoHalf));
Laurence Lundbladeb992fdb2020-07-20 22:44:11 -0700712 ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloatsNoHalf);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700713 (void)spExpectedFloats; // Avoid unused variable error
714#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700715
716 QCBOREncodeContext EC;
717 QCBOREncode_Init(&EC, OutBuffer);
718 QCBOREncode_OpenArray(&EC);
719
720 QCBOREncode_AddDouble(&EC, 0.0);
721 QCBOREncode_AddDouble(&EC, 3.14);
722 QCBOREncode_AddDoubleNoPreferred(&EC, 0.0);
723 QCBOREncode_AddDoubleNoPreferred(&EC, NAN);
724 QCBOREncode_AddDoubleNoPreferred(&EC, INFINITY);
725
726 QCBOREncode_AddFloat(&EC, 0.0);
727 QCBOREncode_AddFloat(&EC, 3.14f);
728 QCBOREncode_AddFloatNoPreferred(&EC, 0.0f);
729 QCBOREncode_AddFloatNoPreferred(&EC, NAN);
730 QCBOREncode_AddFloatNoPreferred(&EC, INFINITY);
731
732 QCBOREncode_OpenMap(&EC);
733
734 QCBOREncode_AddDoubleToMapN(&EC, 100, 0.0);
735 QCBOREncode_AddDoubleToMapN(&EC, 101, 3.1415926);
736 QCBOREncode_AddDoubleToMap(&EC, "euler", 2.71828182845904523536);
737 QCBOREncode_AddDoubleNoPreferredToMapN(&EC, 105, 0.0);
738
739 QCBOREncode_AddFloatToMapN(&EC, 102, 0.0f);
740 QCBOREncode_AddFloatToMapN(&EC, 103, 3.1415926f);
741 QCBOREncode_AddFloatToMap(&EC, "euler2", 2.71828182845904523536f);
742 QCBOREncode_AddFloatNoPreferredToMapN(&EC, 106, 0.0f);
743
744 QCBOREncode_CloseMap(&EC);
745 QCBOREncode_CloseArray(&EC);
746
747 UsefulBufC Encoded;
748 QCBORError uErr = QCBOREncode_Finish(&EC, &Encoded);
749 if(uErr) {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700750 return -1;
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700751 }
752
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700753 if(UsefulBuf_Compare(Encoded, ExpectedFloats)) {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700754 return -3;
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700755 }
756
757 return 0;
758}
759
760
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700761/* returns 0 if equivalent, non-zero if not equivalent */
762static int CHECK_EXPECTED_DOUBLE(double val, double expected)
763{
764 double diff = val - expected;
765
766 diff = fabs(diff);
767
768 if(diff > 0.000001) {
769 return 1;
770 } else {
771 return 0;
772 }
773}
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200774#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700775
Laurence Lundblade755188f2023-12-22 17:40:39 -0700776static int NaNExperiments(void);
777
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700778
Maxim Zhukovd538f0a2022-12-20 20:40:38 +0300779int32_t GeneralFloatDecodeTests(void)
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700780{
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700781 QCBORItem Item;
782 QCBORError uErr;
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700783 QCBORDecodeContext DC;
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700784
Laurence Lundblade755188f2023-12-22 17:40:39 -0700785 NaNExperiments();
786
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700787 UsefulBufC TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
788 QCBORDecode_Init(&DC, TestData, 0);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700789
790 QCBORDecode_GetNext(&DC, &Item);
791 if(Item.uDataType != QCBOR_TYPE_ARRAY) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700792 return MakeTestResultCode(0, 1, 0);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700793 }
794
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700795 /* 0.0 half-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700796 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200797 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
798#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
799 || Item.uDataType != QCBOR_TYPE_DOUBLE
800 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700801#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
802 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200803#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
804 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700805 return MakeTestResultCode(0, 2, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700806 }
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700807
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700808 /* 3.14 double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700809 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200810 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
811#ifndef USEFULBUF_DISABLE_ALL_FLOAT
812 || Item.uDataType != QCBOR_TYPE_DOUBLE
813 || Item.val.dfnum != 3.14
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700814#else /* USEFULBUF_DISABLE_ALL_FLOAT */
815 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200816#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
817 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700818 return MakeTestResultCode(0, 3, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700819 }
820
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700821 /* 0.0 double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700822 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200823 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
824#ifndef USEFULBUF_DISABLE_ALL_FLOAT
825 || Item.uDataType != QCBOR_TYPE_DOUBLE
826 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700827#else /* USEFULBUF_DISABLE_ALL_FLOAT */
828 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200829#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
830 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700831 return MakeTestResultCode(0, 4, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700832 }
833
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700834 /* NaN double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700835 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200836 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
837#ifndef USEFULBUF_DISABLE_ALL_FLOAT
838 || Item.uDataType != QCBOR_TYPE_DOUBLE
839 || !isnan(Item.val.dfnum)
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700840#else /* USEFULBUF_DISABLE_ALL_FLOAT */
841 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200842#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
843 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700844 return MakeTestResultCode(0, 5, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700845 }
846
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700847 /* Infinity double-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700848 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200849 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
850#ifndef USEFULBUF_DISABLE_ALL_FLOAT
851 || Item.uDataType != QCBOR_TYPE_DOUBLE
852 || Item.val.dfnum != INFINITY
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700853#else /* USEFULBUF_DISABLE_ALL_FLOAT */
854 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200855#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
856 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700857 return MakeTestResultCode(0, 6, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700858 }
859
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700860 /* 0.0 half-precision (again) */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700861 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200862 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
863#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
864 || Item.uDataType != QCBOR_TYPE_DOUBLE
865 || Item.val.dfnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700866#else /* USEFULBUF_DISABLE_ALL_FLOAT */
867 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200868#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
869 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700870 return MakeTestResultCode(0, 7, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700871 }
872
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700873 /* 3.140000104904175 single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700874 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200875 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
876#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700877#ifndef QCBOR_DISABLE_FLOAT_HW_USE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200878 || Item.uDataType != QCBOR_TYPE_DOUBLE
879 || CHECK_EXPECTED_DOUBLE(3.14, Item.val.dfnum)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700880#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200881 || Item.uDataType != QCBOR_TYPE_FLOAT
882 || CHECK_EXPECTED_DOUBLE(3.14, Item.val.fnum)
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700883#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
884#else /* USEFULBUF_DISABLE_ALL_FLOAT */
885 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200886#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
887 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700888 return MakeTestResultCode(0, 8, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700889 }
890
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700891 /* 0.0 single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700892 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200893 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
894#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700895#ifndef QCBOR_DISABLE_FLOAT_HW_USE
896 || Item.uDataType != QCBOR_TYPE_DOUBLE
897 || Item.val.dfnum != 0.0
898#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200899 || Item.uDataType != QCBOR_TYPE_FLOAT
900 || Item.val.fnum != 0.0
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700901#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
902#else /* USEFULBUF_DISABLE_ALL_FLOAT */
903 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200904#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
905 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700906 return MakeTestResultCode(0, 9, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700907 }
908
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700909 /* NaN single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700910 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200911 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
912#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700913#ifndef QCBOR_DISABLE_FLOAT_HW_USE
914 || Item.uDataType != QCBOR_TYPE_DOUBLE
915 || !isnan(Item.val.dfnum)
916#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200917 || Item.uDataType != QCBOR_TYPE_FLOAT
918 || !isnan(Item.val.fnum)
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700919#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
920#else /* USEFULBUF_DISABLE_ALL_FLOAT */
921 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200922#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
923 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700924 return MakeTestResultCode(0, 10, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700925 }
926
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700927 /* Infinity single-precision */
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700928 uErr = QCBORDecode_GetNext(&DC, &Item);
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200929 if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
930#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700931#ifndef QCBOR_DISABLE_FLOAT_HW_USE
932 || Item.uDataType != QCBOR_TYPE_DOUBLE
933 || Item.val.dfnum != INFINITY
934#else /* QCBOR_DISABLE_FLOAT_HW_USE */
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200935 || Item.uDataType != QCBOR_TYPE_FLOAT
936 || Item.val.fnum != INFINITY
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700937#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
938#else /* USEFULBUF_DISABLE_ALL_FLOAT */
939 || Item.uDataType != QCBOR_TYPE_NONE
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200940#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
941 ) {
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700942 return MakeTestResultCode(0, 11, uErr);
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700943 }
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700944 /* Sufficent test coverage. Don't need to decode the rest. */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700945
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200946
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +0200947#ifndef USEFULBUF_DISABLE_ALL_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700948 /* Now tests for spiffy decode main function */
949 TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700950 double d;
951 QCBORDecode_Init(&DC, TestData, 0);
Laurence Lundblade6545d1b2020-10-14 11:13:13 -0700952 QCBORDecode_EnterArray(&DC, NULL);
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700953
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700954 /* 0.0 half-precision */
955 QCBORDecode_GetDouble(&DC, &d);
956 uErr = QCBORDecode_GetAndResetError(&DC);
957 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700958#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700959 || d != 0.0
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -0700960#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade16a207a2021-09-18 17:22:46 -0700961 ) {
962 return MakeTestResultCode(1, 1, uErr);
963 }
964
965 /* 3.14 double-precision */
966 QCBORDecode_GetDouble(&DC, &d);
967 uErr = QCBORDecode_GetAndResetError(&DC);
968 if(uErr != QCBOR_SUCCESS || d != 3.14) {
969 return MakeTestResultCode(1, 2, uErr);
970 }
971
972 /* 0.0 double-precision */
973 QCBORDecode_GetDouble(&DC, &d);
974 uErr = QCBORDecode_GetAndResetError(&DC);
975 if(uErr != QCBOR_SUCCESS || d != 0.0) {
976 return MakeTestResultCode(1, 3, uErr);
977 }
978
979 /* NaN double-precision */
980 QCBORDecode_GetDouble(&DC, &d);
981 uErr = QCBORDecode_GetAndResetError(&DC);
982 if(uErr != QCBOR_SUCCESS || !isnan(d)) {
983 return MakeTestResultCode(1, 4, uErr);
984 }
985
986 /* Infinity double-precision */
987 QCBORDecode_GetDouble(&DC, &d);
988 uErr = QCBORDecode_GetAndResetError(&DC);
989 if(uErr != QCBOR_SUCCESS || d != INFINITY) {
990 return MakeTestResultCode(1, 5, uErr);
991 }
992
993 /* 0.0 half-precision */
994 QCBORDecode_GetDouble(&DC, &d);
995 uErr = QCBORDecode_GetAndResetError(&DC);
996 if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
997#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
998 || d != 0.0
999#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
1000 ) {
1001 return MakeTestResultCode(1, 6, uErr);
1002 }
1003
1004 /* 3.140000104904175 single-precision */
1005 QCBORDecode_GetDouble(&DC, &d);
1006 uErr = QCBORDecode_GetAndResetError(&DC);
1007 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1008#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1009 || d != 3.140000104904175
1010#endif
1011 ) {
1012 return MakeTestResultCode(1, 7, uErr);
1013 }
1014
1015 /* 0.0 single-precision */
1016 QCBORDecode_GetDouble(&DC, &d);
1017 uErr = QCBORDecode_GetAndResetError(&DC);
1018 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1019#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1020 || d != 0.0
1021#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1022 ) {
1023 return MakeTestResultCode(1, 8, uErr);
1024 }
1025
1026 /* NaN single-precision */
1027 QCBORDecode_GetDouble(&DC, &d);
1028 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1029#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1030 || !isnan(d)
1031#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1032 ) {
1033 return MakeTestResultCode(1, 9, uErr);
1034 }
1035
1036 /* Infinity single-precision */
1037 QCBORDecode_GetDouble(&DC, &d);
1038 uErr = QCBORDecode_GetAndResetError(&DC);
1039 if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
1040#ifndef QCBOR_DISABLE_FLOAT_HW_USE
1041 || d != INFINITY
1042#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
1043 ) {
1044 return MakeTestResultCode(1, 10, uErr);
1045 }
1046
Máté Tóth-Pálef5f07a2021-09-17 19:31:37 +02001047#endif /* USEFULBUF_DISABLE_ALL_FLOAT */
Laurence Lundbladef7c0adb2020-08-08 20:20:58 -07001048
Laurence Lundblade02fcf312020-07-17 02:49:46 -07001049 return 0;
1050}
1051
1052
Laurence Lundbladed711fb22018-09-26 14:35:22 -07001053
Laurence Lundblade755188f2023-12-22 17:40:39 -07001054//#ifdef NAN_EXPERIMENT
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001055/*
1056 Code for checking what the double to float cast does with
1057 NaNs. Not run as part of tests. Keep it around to
1058 be able to check various platforms and CPUs.
1059 */
1060
Laurence Lundblade755188f2023-12-22 17:40:39 -07001061
1062// ----- Half Precsion -----------
1063#define HALF_NUM_SIGNIFICAND_BITS (10)
1064#define HALF_NUM_EXPONENT_BITS (5)
1065#define HALF_NUM_SIGN_BITS (1)
1066
1067#define HALF_SIGNIFICAND_SHIFT (0)
1068#define HALF_EXPONENT_SHIFT (HALF_NUM_SIGNIFICAND_BITS)
1069#define HALF_SIGN_SHIFT (HALF_NUM_SIGNIFICAND_BITS + HALF_NUM_EXPONENT_BITS)
1070
1071#define HALF_SIGNIFICAND_MASK (0x3ffU) // The lower 10 bits // 0x03ff
1072#define HALF_EXPONENT_MASK (0x1fU << HALF_EXPONENT_SHIFT) // 0x7c00 5 bits of exponent
1073#define HALF_SIGN_MASK (0x01U << HALF_SIGN_SHIFT) // // 0x8000 1 bit of sign
1074#define HALF_QUIET_NAN_BIT (0x01U << (HALF_NUM_SIGNIFICAND_BITS-1)) // 0x0200
1075
1076/* Biased Biased Unbiased Use
1077 0x00 0 -15 0 and subnormal
1078 0x01 1 -14 Smallest normal exponent
1079 0x1e 30 15 Largest normal exponent
1080 0x1F 31 16 NaN and Infinity */
1081#define HALF_EXPONENT_BIAS (15)
1082#define HALF_EXPONENT_MAX (HALF_EXPONENT_BIAS) // 15 Unbiased
1083#define HALF_EXPONENT_MIN (-HALF_EXPONENT_BIAS+1) // -14 Unbiased
1084#define HALF_EXPONENT_ZERO (-HALF_EXPONENT_BIAS) // -15 Unbiased
1085#define HALF_EXPONENT_INF_OR_NAN (HALF_EXPONENT_BIAS+1) // 16 Unbiased
1086
1087
1088// ------ Single-Precision --------
1089#define SINGLE_NUM_SIGNIFICAND_BITS (23)
1090#define SINGLE_NUM_EXPONENT_BITS (8)
1091#define SINGLE_NUM_SIGN_BITS (1)
1092
1093#define SINGLE_SIGNIFICAND_SHIFT (0)
1094#define SINGLE_EXPONENT_SHIFT (SINGLE_NUM_SIGNIFICAND_BITS)
1095#define SINGLE_SIGN_SHIFT (SINGLE_NUM_SIGNIFICAND_BITS + SINGLE_NUM_EXPONENT_BITS)
1096
1097#define SINGLE_SIGNIFICAND_MASK (0x7fffffU) // The lower 23 bits
1098#define SINGLE_EXPONENT_MASK (0xffU << SINGLE_EXPONENT_SHIFT) // 8 bits of exponent
1099#define SINGLE_SIGN_MASK (0x01U << SINGLE_SIGN_SHIFT) // 1 bit of sign
1100#define SINGLE_QUIET_NAN_BIT (0x01U << (SINGLE_NUM_SIGNIFICAND_BITS-1))
1101
1102/* Biased Biased Unbiased Use
1103 0x0000 0 -127 0 and subnormal
1104 0x0001 1 -126 Smallest normal exponent
1105 0x7f 127 0 1
1106 0xfe 254 127 Largest normal exponent
1107 0xff 255 128 NaN and Infinity */
1108#define SINGLE_EXPONENT_BIAS (127)
1109#define SINGLE_EXPONENT_MAX (SINGLE_EXPONENT_BIAS) // 127 unbiased
1110#define SINGLE_EXPONENT_MIN (-SINGLE_EXPONENT_BIAS+1) // -126 unbiased
1111#define SINGLE_EXPONENT_ZERO (-SINGLE_EXPONENT_BIAS) // -127 unbiased
1112#define SINGLE_EXPONENT_INF_OR_NAN (SINGLE_EXPONENT_BIAS+1) // 128 unbiased
1113
1114
1115// --------- Double-Precision ----------
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001116#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
1117#define DOUBLE_NUM_EXPONENT_BITS (11)
1118#define DOUBLE_NUM_SIGN_BITS (1)
1119
1120#define DOUBLE_SIGNIFICAND_SHIFT (0)
1121#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS)
1122#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
1123
1124#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits
1125#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
1126#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
1127#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
1128
1129
Laurence Lundblade755188f2023-12-22 17:40:39 -07001130/* Biased Biased Unbiased Use
1131 0x00000000 0 -1023 0 and subnormal
1132 0x00000001 1 -1022 Smallest normal exponent
1133 0x000007fe 2046 1023 Largest normal exponent
1134 0x000007ff 2047 1024 NaN and Infinity */
1135#define DOUBLE_EXPONENT_BIAS (1023)
1136#define DOUBLE_EXPONENT_MAX (DOUBLE_EXPONENT_BIAS) // unbiased
1137#define DOUBLE_EXPONENT_MIN (-DOUBLE_EXPONENT_BIAS+1) // unbiased
1138#define DOUBLE_EXPONENT_ZERO (-DOUBLE_EXPONENT_BIAS) // unbiased
1139#define DOUBLE_EXPONENT_INF_OR_NAN (DOUBLE_EXPONENT_BIAS+1) // unbiased
1140
1141
1142
1143
1144#include <stdio.h>
1145
1146void nps(uint64_t uPayload)
1147{
1148 double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
1149 double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
1150 double dNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | uPayload);
1151
1152 float f1 = (float)dqNaN;
1153 float f2 = (float)dsNaN;
1154 float f3 = (float)dNaNPayload;
1155
1156
1157 uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
1158 uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
1159 uint32_t uNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dNaNPayload);
1160
1161 uint32_t uSinglePayload = uNaNPayload & SINGLE_SIGNIFICAND_MASK & ~SINGLE_QUIET_NAN_BIT;
1162
1163 // printf("0x%16.16llx 0x%8.8x 0x%8.8x 0x%16.16llx\n", uPayload, uSinglePayload, uNaNPayload, uPayload >> 29);
1164
1165 printf("0x%16.16llx 0x%8.8x\n", uPayload, uSinglePayload);
1166
1167
1168}
1169
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001170static int NaNExperiments() {
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001171
Laurence Lundblade755188f2023-12-22 17:40:39 -07001172 uint64_t uPayload;
1173
1174 for(uPayload = 0x11; uPayload < DOUBLE_SIGNIFICAND_MASK; uPayload *=2) {
1175 nps(uPayload);
1176 }
1177
1178 printf("===============\n");
1179
1180 for(uPayload = 1; uPayload < DOUBLE_SIGNIFICAND_MASK; uPayload *=2 ) {
1181 nps(uPayload);
1182 }
1183
1184 printf("===============\n");
1185
1186 for(int i = 0 ; i < 50; i++) {
1187 nps(0x123456789abcdULL >> i);
1188 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001189
1190
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001191
Laurence Lundblade755188f2023-12-22 17:40:39 -07001192
Laurence Lundblade3aee3a32018-12-17 16:17:45 -08001193
Laurence Lundblade7d40d812018-09-30 02:44:01 -07001194 return 0;
1195}
Laurence Lundblade755188f2023-12-22 17:40:39 -07001196//#endif /* NAN_EXPERIMENT */