blob: 8886ab8ca0673239365cbe994b8be73a6fd66478 [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.
Laurence Lundblade035bd782019-01-21 17:01:31 -08005
Laurence Lundbladea3fd49f2019-01-21 10:16:22 -08006 SPDX-License-Identifier: BSD-3-Clause
Laurence Lundblade035bd782019-01-21 17:01:31 -08007
Laurence Lundbladea3fd49f2019-01-21 10:16:22 -08008 See BSD-3-Clause license in README.md
Laurence Lundblade035bd782019-01-21 17:01:31 -08009
Laurence Lundbladea3fd49f2019-01-21 10:16:22 -080010 Created on 9/19/18
Laurence Lundbladeee851742020-01-08 08:37:05 -080011 =============================================================================*/
Laurence Lundblade68a13352018-09-23 02:19:54 -070012
Laurence Lundblade2aa0b572020-07-16 19:48:42 -070013
14#include "float_tests.h"
Laurence Lundblade585127a2020-07-15 03:25:24 -070015#include "qcbor/qcbor_encode.h"
Laurence Lundblade02fcf312020-07-17 02:49:46 -070016#include "qcbor/qcbor_decode.h"
Laurence Lundblade585127a2020-07-15 03:25:24 -070017#include <math.h> // For INFINITY and NAN and isnan()
18
Laurence Lundbladeb275cdc2020-07-12 12:34:38 -070019#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade9682a532020-06-06 18:33:04 -070020
Laurence Lundbladed711fb22018-09-26 14:35:22 -070021#include "half_to_double_from_rfc7049.h"
Laurence Lundblade68a13352018-09-23 02:19:54 -070022
Laurence Lundblade2d85ce42018-10-12 14:12:47 +080023
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070024// A series of half precision values to test half-precision decoding
25/*
26 As decoded by http://cbor.me
27 {"zero": 0.0,
28 "infinitity": Infinity,
29 "negative infinitity": -Infinity,
30 "NaN": NaN,
31 "one": 1.0,
32 "one third": 0.333251953125,
33 "largest half-precision": 65504.0,
34 "too-large half-precision": Infinity,
35 "smallest subnormal": 5.960464477539063e-8,
36 "smallest normal": 0.00006097555160522461,
37 "biggest subnormal": 0.00006103515625,
38 "subnormal single": 0.0,
39 3: -2.0,
40 4: NaN,
41 5: NaN,
42 6: NaN,
43 7: NaN}
44 */
Laurence Lundbladebb474be2018-10-22 11:53:21 +053045static const uint8_t spExpectedHalf[] = {
Laurence Lundblade7d40d812018-09-30 02:44:01 -070046 0xB1,
Laurence Lundblade68a13352018-09-23 02:19:54 -070047 0x64,
48 0x7A, 0x65, 0x72, 0x6F,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070049 0xF9, 0x00, 0x00, // half-precision 0.000
Laurence Lundblade68a13352018-09-23 02:19:54 -070050 0x6A,
51 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070052 0xF9, 0x7C, 0x00, // Infinity
Laurence Lundblade68a13352018-09-23 02:19:54 -070053 0x73,
Laurence Lundbladeee851742020-01-08 08:37:05 -080054 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E,
55 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070056 0xF9, 0xFC, 0x00, // -Inifinity
Laurence Lundblade68a13352018-09-23 02:19:54 -070057 0x63,
58 0x4E, 0x61, 0x4E,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070059 0xF9, 0x7E, 0x00, // NaN
Laurence Lundblade68a13352018-09-23 02:19:54 -070060 0x63,
61 0x6F, 0x6E, 0x65,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070062 0xF9, 0x3C, 0x00, // 1.0
Laurence Lundblade68a13352018-09-23 02:19:54 -070063 0x69,
64 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070065 0xF9, 0x35, 0x55, // half-precsion one third 0.333251953125
Laurence Lundblade68a13352018-09-23 02:19:54 -070066 0x76,
Laurence Lundbladeee851742020-01-08 08:37:05 -080067 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C,
68 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070069 0xF9, 0x7B, 0xFF, // largest half-precision 65504.0
Laurence Lundbladeee851742020-01-08 08:37:05 -080070 0x78, 0x18,
71 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x68,
72 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69,
73 0x6F, 0x6E,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070074 0xF9, 0x7C, 0x00, // Infinity
Laurence Lundblade68a13352018-09-23 02:19:54 -070075 0x72,
Laurence Lundbladeee851742020-01-08 08:37:05 -080076 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75,
77 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070078 0xF9, 0x00, 0x01, // Smallest half-precision subnormal 0.000000059604645
Laurence Lundblade68a13352018-09-23 02:19:54 -070079 0x71,
Laurence Lundbladeee851742020-01-08 08:37:05 -080080 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62,
81 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -070082 0xF9, 0x03, 0xFF, // Largest half-precision subnormal 0.0000609755516
83 0x6F,
84 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F,
85 0x72, 0x6D, 0x61, 0x6C,
86 0xF9, 0x04, 0x00, // Smallest half-precision normal 0.000061988
Laurence Lundblade68a13352018-09-23 02:19:54 -070087 0x70,
Laurence Lundbladeee851742020-01-08 08:37:05 -080088 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73,
89 0x69, 0x6E, 0x67, 0x6C, 0x65,
Laurence Lundblade68a13352018-09-23 02:19:54 -070090 0xF9, 0x00, 0x00,
91 0x03,
Laurence Lundblade7d40d812018-09-30 02:44:01 -070092 0xF9, 0xC0, 0x00, // -2
93 0x04,
94 0xF9, 0x7E, 0x00, // qNaN
95 0x05,
96 0xF9, 0x7C, 0x01, // sNaN
97 0x06,
98 0xF9, 0x7E, 0x0F, // qNaN with payload 0x0f
99 0x07,
100 0xF9, 0x7C, 0x0F, // sNaN with payload 0x0f
Laurence Lundblade68a13352018-09-23 02:19:54 -0700101};
102
103
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800104int32_t HalfPrecisionDecodeBasicTests()
Laurence Lundblade68a13352018-09-23 02:19:54 -0700105{
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700106 UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800107
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700108 QCBORDecodeContext DC;
109 QCBORDecode_Init(&DC, HalfPrecision, 0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800110
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700111 QCBORItem Item;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700112
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700113 QCBORDecode_GetNext(&DC, &Item);
114 if(Item.uDataType != QCBOR_TYPE_MAP) {
115 return -1;
116 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700117
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700118 QCBORDecode_GetNext(&DC, &Item);
119 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0) {
120 return -2;
121 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800122
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700123 QCBORDecode_GetNext(&DC, &Item);
124 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
125 return -3;
126 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700127
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700128 QCBORDecode_GetNext(&DC, &Item);
129 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -INFINITY) {
130 return -4;
131 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700132
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700133 // TODO: NAN-related is this really converting right? It is carrying payload, but
134 // this confuses things.
135 QCBORDecode_GetNext(&DC, &Item);
136 if(Item.uDataType != QCBOR_TYPE_DOUBLE || !isnan(Item.val.dfnum)) {
137 return -5;
138 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700139
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700140 QCBORDecode_GetNext(&DC, &Item);
141 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 1.0) {
142 return -6;
143 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800144
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700145 // Approximately 1/3
146 QCBORDecode_GetNext(&DC, &Item);
147 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.333251953125) {
148 return -7;
149 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700150
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700151 // Largest half-precision
152 QCBORDecode_GetNext(&DC, &Item);
153 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 65504.0) {
154 return -8;
155 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700156
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700157 QCBORDecode_GetNext(&DC, &Item);
158 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
159 return -9;
160 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800161
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700162 // Smallest half-precision subnormal
163 QCBORDecode_GetNext(&DC, &Item);
164 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00000005960464477539063) {
165 return -10;
166 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700167
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700168 // Largest half-precision subnormal
169 QCBORDecode_GetNext(&DC, &Item);
170 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00006097555160522461) {
171 return -11;
172 }
Laurence Lundblade68a13352018-09-23 02:19:54 -0700173
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700174 // Smallest half-precision normal
175 QCBORDecode_GetNext(&DC, &Item);
176 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00006103515625) {
177 return -12;
178 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800179
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700180 // half-precision zero
181 QCBORDecode_GetNext(&DC, &Item);
182 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0) {
183 return -13;
184 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800185
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700186 // negative 2
187 QCBORDecode_GetNext(&DC, &Item);
188 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -2.0) {
189 return -14;
190 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800191
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700192 // TODO: NAN-related double check these four tests
193 QCBORDecode_GetNext(&DC, &Item); // qNaN
194 if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
195 UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff8000000000000ULL) {
196 return -15;
197 }
198 QCBORDecode_GetNext(&DC, &Item); // sNaN
199 if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
200 UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff0000000000001ULL) {
201 return -16;
202 }
203 QCBORDecode_GetNext(&DC, &Item); // qNaN with payload 0x0f
204 if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
205 UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff800000000000fULL) {
206 return -17;
207 }
208 QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f
209 if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
210 UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff000000000000fULL) {
211 return -18;
212 }
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700213
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700214 if(QCBORDecode_Finish(&DC)) {
215 return -19;
216 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800217
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700218 return 0;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700219}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700220
221
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700222
223
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800224int32_t HalfPrecisionAgainstRFCCodeTest()
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700225{
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700226 for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700227 unsigned char x[2];
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800228 x[1] = (uint8_t)(uHalfP & 0xff);
229 x[0] = (uint8_t)(uHalfP >> 8); // uHalfP is always less than 0xffff
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700230 double d = decode_half(x);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800231
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700232 // Contruct the CBOR for the half-precision float by hand
Laurence Lundblade4fe9f312018-10-22 10:22:39 +0530233 UsefulBuf_MAKE_STACK_UB(__xx, 3);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700234 UsefulOutBuf UOB;
235 UsefulOutBuf_Init(&UOB, __xx);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800236
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800237 const uint8_t uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); // 0xf9
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700238 UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float
239 UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP);
240
Laurence Lundbladeee851742020-01-08 08:37:05 -0800241 // Now parse the hand-constructed CBOR. This will invoke the
242 // conversion to a float
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700243 QCBORDecodeContext DC;
244 QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800245
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700246 QCBORItem Item;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800247
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700248 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700249 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700250 return -1;
251 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800252
Laurence Lundbladeee851742020-01-08 08:37:05 -0800253 //printf("%04x QCBOR:%15.15f RFC: %15.15f (%8x)\n",
254 // uHalfP, Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800255
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700256 if(isnan(d)) {
257 // The RFC code uses the native instructions which may or may not
258 // handle sNaN, qNaN and NaN payloads correctly. This test just
259 // makes sure it is a NaN and doesn't worry about the type of NaN
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700260 if(!isnan(Item.val.dfnum)) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700261 return -3;
262 }
263 } else {
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700264 if(Item.val.dfnum != d) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700265 return -2;
266 }
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700267 }
268 }
269 return 0;
270}
271
272
273/*
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530274 {"zero": 0.0,
275 "negative zero": -0.0,
276 "infinitity": Infinity,
277 "negative infinitity": -Infinity,
278 "NaN": NaN,
279 "one": 1.0,
280 "one third": 0.333251953125,
281 "largest half-precision": 65504.0,
282 "largest half-precision point one": 65504.1,
283 "too-large half-precision": 65536.0,
284 "smallest subnormal": 5.96046448e-8,
285 "smallest normal": 0.00006103515261202119,
286 "biggest subnormal": 0.00006103515625,
287 "subnormal single": 4.00000646641519e-40,
288 3: -2.0,
289 "large single exp": 2.5521177519070385e+38,
290 "too-large single exp": 5.104235503814077e+38,
291 "biggest single with prec": 16777216.0,
292 "first single with prec loss": 16777217.0,
293 1: "fin"}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700294 */
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530295static const uint8_t spExpectedSmallest[] = {
296 0xB4, 0x64, 0x7A, 0x65, 0x72, 0x6F, 0xF9, 0x00, 0x00, 0x6D,
297 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x7A,
298 0x65, 0x72, 0x6F, 0xF9, 0x80, 0x00, 0x6A, 0x69, 0x6E, 0x66,
299 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, 0xF9, 0x7C, 0x00,
300 0x73, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20,
301 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
302 0xF9, 0xFC, 0x00, 0x63, 0x4E, 0x61, 0x4E, 0xF9, 0x7E, 0x00,
303 0x63, 0x6F, 0x6E, 0x65, 0xF9, 0x3C, 0x00, 0x69, 0x6F, 0x6E,
304 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, 0xF9, 0x35, 0x55,
305 0x76, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68,
306 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73,
307 0x69, 0x6F, 0x6E, 0xF9, 0x7B, 0xFF, 0x78, 0x20, 0x6C, 0x61,
308 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66,
309 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
310 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x65,
311 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33, 0x78,
312 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65,
313 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63,
314 0x69, 0x73, 0x69, 0x6F, 0x6E, 0xFA, 0x47, 0x80, 0x00, 0x00,
315 0x72, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20,
316 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xFB,
317 0x3E, 0x70, 0x00, 0x00, 0x00, 0x1C, 0x5F, 0x68, 0x6F, 0x73,
318 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F,
319 0x72, 0x6D, 0x61, 0x6C, 0xFA, 0x38, 0x7F, 0xFF, 0xFF, 0x71,
320 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75,
321 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xF9, 0x04, 0x00,
322 0x70, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
323 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0xFB, 0x37, 0xC1,
324 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF9, 0xC0, 0x00,
325 0x70, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E,
326 0x67, 0x6C, 0x65, 0x20, 0x65, 0x78, 0x70, 0xFA, 0x7F, 0x40,
327 0x00, 0x00, 0x74, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72,
328 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
329 0x65, 0x78, 0x70, 0xFB, 0x47, 0xF8, 0x00, 0x00, 0x00, 0x00,
330 0x00, 0x00, 0x78, 0x18, 0x62, 0x69, 0x67, 0x67, 0x65, 0x73,
331 0x74, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77,
332 0x69, 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0xFA, 0x4B,
333 0x80, 0x00, 0x00, 0x78, 0x1B, 0x66, 0x69, 0x72, 0x73, 0x74,
334 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, 0x69,
335 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x20, 0x6C, 0x6F,
336 0x73, 0x73, 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00,
337 0x00, 0x01, 0x63, 0x66, 0x69, 0x6E
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700338};
339
340
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800341int32_t DoubleAsSmallestTest()
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700342{
Laurence Lundblade4fe9f312018-10-22 10:22:39 +0530343 UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, 420);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800344
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700345#define QCBOREncode_AddDoubleToMap QCBOREncode_AddDoubleToMap
Laurence Lundblade067035b2018-11-28 17:35:25 -0800346
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800347
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700348 QCBOREncodeContext EC;
349 QCBOREncode_Init(&EC, EncodedHalfsMem);
350 // These are mostly from https://en.wikipedia.org/wiki/Half-precision_floating-point_format
351 QCBOREncode_OpenMap(&EC);
352 // 64 # text(4)
353 // 7A65726F # "zero"
354 // F9 0000 # primitive(0)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700355 QCBOREncode_AddDoubleToMap(&EC, "zero", 0.00);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700356
357 // 64 # text(4)
358 // 7A65726F # "negative zero"
359 // F9 8000 # primitive(0)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700360 QCBOREncode_AddDoubleToMap(&EC, "negative zero", -0.00);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800361
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700362 // 6A # text(10)
363 // 696E66696E6974697479 # "infinitity"
364 // F9 7C00 # primitive(31744)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700365 QCBOREncode_AddDoubleToMap(&EC, "infinitity", INFINITY);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800366
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700367 // 73 # text(19)
368 // 6E6567617469766520696E66696E6974697479 # "negative infinitity"
369 // F9 FC00 # primitive(64512)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700370 QCBOREncode_AddDoubleToMap(&EC, "negative infinitity", -INFINITY);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800371
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700372 // 63 # text(3)
373 // 4E614E # "NaN"
374 // F9 7E00 # primitive(32256)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700375 QCBOREncode_AddDoubleToMap(&EC, "NaN", NAN);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800376
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700377 // TODO: test a few NaN variants
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800378
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700379 // 63 # text(3)
380 // 6F6E65 # "one"
381 // F9 3C00 # primitive(15360)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700382 QCBOREncode_AddDoubleToMap(&EC, "one", 1.0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800383
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700384 // 69 # text(9)
385 // 6F6E65207468697264 # "one third"
386 // F9 3555 # primitive(13653)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700387 QCBOREncode_AddDoubleToMap(&EC, "one third", 0.333251953125);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800388
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700389 // 76 # text(22)
Laurence Lundbladeee851742020-01-08 08:37:05 -0800390 // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700391 // F9 7BFF # primitive(31743)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700392 QCBOREncode_AddDoubleToMap(&EC, "largest half-precision",65504.0);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700393
394 // 76 # text(22)
Laurence Lundbladeee851742020-01-08 08:37:05 -0800395 // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700396 // F9 7BFF # primitive(31743)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700397 QCBOREncode_AddDoubleToMap(&EC, "largest half-precision point one",65504.1);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800398
Laurence Lundbladeee851742020-01-08 08:37:05 -0800399 // Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which
400 // is larger than 15, the largest half-precision exponent
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700401 // 78 18 # text(24)
402 // 746F6F2D6C617267652068616C662D707265636973696F6E # "too-large half-precision"
403 // FA 47800000 # primitive(31743)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700404 QCBOREncode_AddDoubleToMap(&EC, "too-large half-precision", 65536.0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800405
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700406 // The smallest possible half-precision subnormal, but digitis are lost converting
407 // to half, so this turns into a double
408 // 72 # text(18)
409 // 736D616C6C657374207375626E6F726D616C # "smallest subnormal"
410 // FB 3E700000001C5F68 # primitive(4499096027744984936)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700411 QCBOREncode_AddDoubleToMap(&EC, "smallest subnormal", 0.0000000596046448);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800412
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700413 // The smallest possible half-precision snormal, but digitis are lost converting
414 // to half, so this turns into a single TODO: confirm this is right
415 // 6F # text(15)
416 // 736D616C6C657374206E6F726D616C # "smallest normal"
417 // FA 387FFFFF # primitive(947912703)
418 // in hex single is 0x387fffff, exponent -15, significand 7fffff
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700419 QCBOREncode_AddDoubleToMap(&EC, "smallest normal", 0.0000610351526F);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800420
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700421 // 71 # text(17)
422 // 62696767657374207375626E6F726D616C # "biggest subnormal"
423 // F9 0400 # primitive(1024)
424 // in hex single is 0x38800000, exponent -14, significand 0
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700425 QCBOREncode_AddDoubleToMap(&EC, "biggest subnormal", 0.0000610351563F);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800426
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700427 // 70 # text(16)
428 // 7375626E6F726D616C2073696E676C65 # "subnormal single"
429 // FB 37C16C2800000000 # primitive(4017611261645684736)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700430 QCBOREncode_AddDoubleToMap(&EC, "subnormal single", 4e-40F);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800431
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700432 // 03 # unsigned(3)
433 // F9 C000 # primitive(49152)
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700434 QCBOREncode_AddDoubleToMapN(&EC, 3, -2.0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800435
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700436 // 70 # text(16)
437 // 6C617267652073696E676C6520657870 # "large single exp"
438 // FA 7F400000 # primitive(2134900736)
439 // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((127LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT);
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700440 QCBOREncode_AddDoubleToMap(&EC, "large single exp", 2.5521177519070385E+38); // Exponent fits single
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700441
442 // 74 # text(20)
443 // 746F6F2D6C617267652073696E676C6520657870 # "too-large single exp"
444 // FB 47F8000000000000 # primitive(5185894970917126144)
445 // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((128LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT);
Laurence Lundbladeee851742020-01-08 08:37:05 -0800446 // Exponent too large for single
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700447 QCBOREncode_AddDoubleToMap(&EC, "too-large single exp", 5.104235503814077E+38);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700448
449 // 66 # text(6)
450 // 646664666465 # "dfdfde"
451 // FA 4B800000 # primitive(1266679808)
Laurence Lundbladeee851742020-01-08 08:37:05 -0800452 // Single with no precision loss
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700453 QCBOREncode_AddDoubleToMap(&EC, "biggest single with prec", 16777216);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800454
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700455 // 78 18 # text(24)
456 // 626967676573742073696E676C6520776974682070726563 # "biggest single with prec"
457 // FA 4B800000 # primitive(1266679808)
Laurence Lundbladeee851742020-01-08 08:37:05 -0800458 // Double becuase of precision loss
Laurence Lundblade6d3f6ec2020-07-18 17:28:26 -0700459 QCBOREncode_AddDoubleToMap(&EC, "first single with prec loss", 16777217);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800460
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700461 // Just a convenient marker when cutting and pasting encoded CBOR
462 QCBOREncode_AddSZStringToMapN(&EC, 1, "fin");
463
464 QCBOREncode_CloseMap(&EC);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800465
Laurence Lundblade781fd822018-10-01 09:37:52 -0700466 UsefulBufC EncodedHalfs;
Laurence Lundblade29497c02020-07-11 15:44:03 -0700467 QCBORError uErr = QCBOREncode_Finish(&EC, &EncodedHalfs);
468 if(uErr) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700469 return -1;
470 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800471
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530472 if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700473 return -3;
474 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800475
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700476 return 0;
Laurence Lundblade570fab52018-10-13 18:28:27 +0800477}
Laurence Lundblade585127a2020-07-15 03:25:24 -0700478#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700479
480
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700481/*
482[0.0, 3.14, 0.0, NaN, Infinity, 0.0, 3.140000104904175, 0.0, NaN, Infinity,
483 {100: 0.0, 101: 3.1415926, "euler": 2.718281828459045, 105: 0.0,
484 102: 0.0, 103: 3.141592502593994, "euler2": 2.7182817459106445, 106: 0.0}]
485 */
486static const uint8_t spExpectedFloats[] = {
487 0x8B,
488 0xF9, 0x00, 0x00,
489 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
490 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
491 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
492 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
493 0xF9, 0x00, 0x00,
494 0xFA, 0x40, 0x48, 0xF5, 0xC3,
495 0xFA, 0x00, 0x00, 0x00, 0x00,
496 0xFA, 0x7F, 0xC0, 0x00, 0x00,
497 0xFA, 0x7F, 0x80, 0x00, 0x00,
498 0xA8,
499 0x18, 0x64,
500 0xF9, 0x00, 0x00,
501 0x18, 0x65,
502 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
503 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
504 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
505 0x18, 0x69,
506 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
507 0x18, 0x66,
508 0xF9, 0x00, 0x00,
509 0x18, 0x67,
510 0xFA, 0x40, 0x49, 0x0F, 0xDA,
511 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
512 0xFA, 0x40, 0x2D, 0xF8, 0x54,
513 0x18, 0x6A,
514 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700515
516static const uint8_t spExpectedFloatsNoHalf[] = {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700517 0x8B,
518 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
519 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
520 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
521 0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
522 0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
523 0xFA, 0x00, 0x00, 0x00, 0x00,
524 0xFA, 0x40, 0x48, 0xF5, 0xC3,
525 0xFA, 0x00, 0x00, 0x00, 0x00,
526 0xFA, 0x7F, 0xC0, 0x00, 0x00,
527 0xFA, 0x7F, 0x80, 0x00, 0x00,
528 0xA8,
529 0x18, 0x64,
530 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
531 0x18, 0x65,
532 0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
533 0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
534 0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
535 0x18, 0x69,
536 0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
537 0x18, 0x66,
538 0xFA, 0x00, 0x00, 0x00, 0x00,
539 0x18, 0x67,
540 0xFA, 0x40, 0x49, 0x0F, 0xDA,
541 0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
542 0xFA, 0x40, 0x2D, 0xF8, 0x54,
543 0x18, 0x6A,
544 0xFA, 0x00, 0x00, 0x00, 0x00};
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700545
546int32_t GeneralFloatEncodeTests()
547{
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700548#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700549 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloats));
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700550 UsefulBufC ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
551 (void)spExpectedFloatsNoHalf; // Avoid unused variable error
552#else
553 UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloatsNoHalf));
554 UsefulBufC ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloatsNoHalf);
555 (void)spExpectedFloats; // Avoid unused variable error
556#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700557
558 QCBOREncodeContext EC;
559 QCBOREncode_Init(&EC, OutBuffer);
560 QCBOREncode_OpenArray(&EC);
561
562 QCBOREncode_AddDouble(&EC, 0.0);
563 QCBOREncode_AddDouble(&EC, 3.14);
564 QCBOREncode_AddDoubleNoPreferred(&EC, 0.0);
565 QCBOREncode_AddDoubleNoPreferred(&EC, NAN);
566 QCBOREncode_AddDoubleNoPreferred(&EC, INFINITY);
567
568 QCBOREncode_AddFloat(&EC, 0.0);
569 QCBOREncode_AddFloat(&EC, 3.14f);
570 QCBOREncode_AddFloatNoPreferred(&EC, 0.0f);
571 QCBOREncode_AddFloatNoPreferred(&EC, NAN);
572 QCBOREncode_AddFloatNoPreferred(&EC, INFINITY);
573
574 QCBOREncode_OpenMap(&EC);
575
576 QCBOREncode_AddDoubleToMapN(&EC, 100, 0.0);
577 QCBOREncode_AddDoubleToMapN(&EC, 101, 3.1415926);
578 QCBOREncode_AddDoubleToMap(&EC, "euler", 2.71828182845904523536);
579 QCBOREncode_AddDoubleNoPreferredToMapN(&EC, 105, 0.0);
580
581 QCBOREncode_AddFloatToMapN(&EC, 102, 0.0f);
582 QCBOREncode_AddFloatToMapN(&EC, 103, 3.1415926f);
583 QCBOREncode_AddFloatToMap(&EC, "euler2", 2.71828182845904523536f);
584 QCBOREncode_AddFloatNoPreferredToMapN(&EC, 106, 0.0f);
585
586 QCBOREncode_CloseMap(&EC);
587 QCBOREncode_CloseArray(&EC);
588
589 UsefulBufC Encoded;
590 QCBORError uErr = QCBOREncode_Finish(&EC, &Encoded);
591 if(uErr) {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700592 return -1;
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700593 }
594
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700595 if(UsefulBuf_Compare(Encoded, ExpectedFloats)) {
Laurence Lundblade585127a2020-07-15 03:25:24 -0700596 return -3;
Laurence Lundblade32f3e622020-07-13 20:35:11 -0700597 }
598
599 return 0;
600}
601
602
Laurence Lundblade02fcf312020-07-17 02:49:46 -0700603#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
604/* returns 0 if equivalent, non-zero if not equivalent */
605static int CHECK_EXPECTED_DOUBLE(double val, double expected)
606{
607 double diff = val - expected;
608
609 diff = fabs(diff);
610
611 if(diff > 0.000001) {
612 return 1;
613 } else {
614 return 0;
615 }
616}
617#endif
618
619
620int32_t GeneralFloatDecodeTests()
621{
622 UsefulBufC TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
623
624 QCBORDecodeContext DC;
625 QCBORDecode_Init(&DC, TestData, 0);
626
627 QCBORItem Item;
628 QCBORError uErr;
629
630 QCBORDecode_GetNext(&DC, &Item);
631 if(Item.uDataType != QCBOR_TYPE_ARRAY) {
632 return -1;
633 }
634
635#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
636 uErr = QCBORDecode_GetNext(&DC, &Item);
637 if(uErr != QCBOR_SUCCESS ||
638 Item.uDataType != QCBOR_TYPE_DOUBLE ||
639 Item.val.dfnum != 0.0) {
640 return -2;
641 }
642#else
643 uErr = QCBORDecode_GetNext(&DC, &Item);
644 if(uErr != QCBOR_ERR_HALF_PRECISION_UNSUPPORTED) {
645 return -3;
646 }
647#endif
648
649 uErr = QCBORDecode_GetNext(&DC, &Item);
650 if(uErr != QCBOR_SUCCESS ||
651 Item.uDataType != QCBOR_TYPE_DOUBLE ||
652 Item.val.dfnum != 3.14) {
653 return -4;
654 }
655
656 uErr = QCBORDecode_GetNext(&DC, &Item);
657 if(uErr != QCBOR_SUCCESS ||
658 Item.uDataType != QCBOR_TYPE_DOUBLE ||
659 Item.val.dfnum != 0.0) {
660 return -5;
661 }
662
663 uErr = QCBORDecode_GetNext(&DC, &Item);
664 if(uErr != QCBOR_SUCCESS ||
665 Item.uDataType != QCBOR_TYPE_DOUBLE ||
666 !isnan(Item.val.dfnum)) {
667 return -6;
668 }
669
670 uErr = QCBORDecode_GetNext(&DC, &Item);
671 if(uErr != QCBOR_SUCCESS ||
672 Item.uDataType != QCBOR_TYPE_DOUBLE ||
673 Item.val.dfnum != INFINITY) {
674 return -7;
675 }
676
677#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
678 uErr = QCBORDecode_GetNext(&DC, &Item);
679 if(uErr != QCBOR_SUCCESS ||
680 Item.uDataType != QCBOR_TYPE_DOUBLE ||
681 Item.val.dfnum != 0.0) {
682 return -8;
683 }
684
685 uErr = QCBORDecode_GetNext(&DC, &Item);
686 if(uErr != QCBOR_SUCCESS ||
687 Item.uDataType != QCBOR_TYPE_DOUBLE ||
688 CHECK_EXPECTED_DOUBLE(3.14, Item.val.dfnum)) {
689 return -9;
690 }
691
692 uErr = QCBORDecode_GetNext(&DC, &Item);
693 if(uErr != QCBOR_SUCCESS ||
694 Item.uDataType != QCBOR_TYPE_DOUBLE ||
695 Item.val.dfnum != 0.0) {
696 return -10;
697 }
698
699 uErr = QCBORDecode_GetNext(&DC, &Item);
700 if(uErr != QCBOR_SUCCESS ||
701 Item.uDataType != QCBOR_TYPE_DOUBLE ||
702 !isnan(Item.val.dfnum)) {
703 return -11;
704 }
705
706 uErr = QCBORDecode_GetNext(&DC, &Item);
707 if(uErr != QCBOR_SUCCESS ||
708 Item.uDataType != QCBOR_TYPE_DOUBLE ||
709 Item.val.dfnum != INFINITY) {
710 return -12;
711 }
712
713#else
714 uErr = QCBORDecode_GetNext(&DC, &Item);
715 if(uErr != QCBOR_ERR_HALF_PRECISION_UNSUPPORTED) {
716 return -13;
717 }
718
719 uErr = QCBORDecode_GetNext(&DC, &Item);
720 if(uErr != QCBOR_SUCCESS ||
721 Item.uDataType != QCBOR_TYPE_FLOAT ||
722 Item.val.fnum != 3.14f) {
723 return -14;
724 }
725
726 uErr = QCBORDecode_GetNext(&DC, &Item);
727 if(uErr != QCBOR_SUCCESS ||
728 Item.uDataType != QCBOR_TYPE_FLOAT ||
729 Item.val.fnum != 0.0f) {
730 return -15;
731 }
732
733 uErr = QCBORDecode_GetNext(&DC, &Item);
734 if(uErr != QCBOR_SUCCESS ||
735 Item.uDataType != QCBOR_TYPE_FLOAT ||
736 !isnan(Item.val.fnum)) {
737 return -16;
738 }
739
740 uErr = QCBORDecode_GetNext(&DC, &Item);
741 if(uErr != QCBOR_SUCCESS ||
742 Item.uDataType != QCBOR_TYPE_FLOAT ||
743 Item.val.fnum != INFINITY) {
744 return -17;
745 }
746#endif
747 /* Sufficent test coverage. Don't need to decode the rest */
748
749 return 0;
750}
751
752
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700753
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700754#ifdef NAN_EXPERIMENT
755/*
756 Code for checking what the double to float cast does with
757 NaNs. Not run as part of tests. Keep it around to
758 be able to check various platforms and CPUs.
759 */
760
761#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
762#define DOUBLE_NUM_EXPONENT_BITS (11)
763#define DOUBLE_NUM_SIGN_BITS (1)
764
765#define DOUBLE_SIGNIFICAND_SHIFT (0)
766#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS)
767#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
768
769#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits
770#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
771#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
772#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
773
774
775static int NaNExperiments() {
776 double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
777 double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
778 double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800779
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700780 float f1 = (float)dqNaN;
781 float f2 = (float)dsNaN;
782 float f3 = (float)dqNaNPayload;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800783
784
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700785 uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
786 uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
787 uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800788
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700789 // Result of this on x86 is that every NaN is a qNaN. The intel
790 // CVTSD2SS instruction ignores the NaN payload and even converts
791 // a sNaN to a qNaN.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800792
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700793 return 0;
794}
795#endif
796
797
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700798