blob: a1c8c8d9eed328d53d1730b5a48f688d4dbec472 [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 Lundbladed92a6162018-11-01 11:38:35 +07004 Copyright (c) 2018, Laurence Lundblade.
5 All rights reserved.
Laurence Lundblade68a13352018-09-23 02:19:54 -07006
Laurence Lundblade0dbc9172018-11-01 14:17:21 +07007Redistribution and use in source and binary forms, with or without
8modification, are permitted provided that the following conditions are
9met:
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above
13 copyright notice, this list of conditions and the following
14 disclaimer in the documentation and/or other materials provided
15 with the distribution.
16 * The name "Laurence Lundblade" may not be used to
17 endorse or promote products derived from this software without
18 specific prior written permission.
Laurence Lundblade68a13352018-09-23 02:19:54 -070019
Laurence Lundblade0dbc9172018-11-01 14:17:21 +070020THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundblade68a13352018-09-23 02:19:54 -070031 ==============================================================================*/
Laurence Lundblade68a13352018-09-23 02:19:54 -070032// Created by Laurence Lundblade on 9/19/18.
Laurence Lundblade781fd822018-10-01 09:37:52 -070033
Laurence Lundblade68a13352018-09-23 02:19:54 -070034
Laurence Lundblade2d85ce42018-10-12 14:12:47 +080035#include "float_tests.h"
Laurence Lundblade68a13352018-09-23 02:19:54 -070036#include "qcbor.h"
Laurence Lundbladed711fb22018-09-26 14:35:22 -070037#include "half_to_double_from_rfc7049.h"
38#include <math.h> // For INFINITY and NAN and isnan()
Laurence Lundblade68a13352018-09-23 02:19:54 -070039
Laurence Lundblade2d85ce42018-10-12 14:12:47 +080040
Laurence Lundblade2d85ce42018-10-12 14:12:47 +080041
Laurence Lundbladebb474be2018-10-22 11:53:21 +053042static const uint8_t spExpectedHalf[] = {
Laurence Lundblade7d40d812018-09-30 02:44:01 -070043 0xB1,
Laurence Lundblade68a13352018-09-23 02:19:54 -070044 0x64,
45 0x7A, 0x65, 0x72, 0x6F,
46 0xF9, 0x00, 0x00, // 0.000
47 0x6A,
48 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
49 0xF9, 0x7C, 0x00, // Infinity
50 0x73,
51 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
52 0xF9, 0xFC, 0x00, // -Inifinity
53 0x63,
54 0x4E, 0x61, 0x4E,
55 0xF9, 0x7E, 0x00, // NaN
56 0x63,
57 0x6F, 0x6E, 0x65,
58 0xF9, 0x3C, 0x00, // 1.0
59 0x69,
60 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64,
61 0xF9, 0x35, 0x55, // 0.333251953125
62 0x76,
63 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
64 0xF9, 0x7B, 0xFF, // 65504.0
65 0x78, 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
66 0xF9, 0x7C, 0x00, // Infinity
67 0x72,
68 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
69 0xF9, 0x00, 0x01, // 0.000000059604
70 0x6F,
71 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
72 0xF9, 0x03, 0xFF, // 0.0000609755516
73 0x71,
74 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
75 0xF9, 0x04, 0x00, // 0.000061988
76 0x70,
77 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65,
78 0xF9, 0x00, 0x00,
79 0x03,
Laurence Lundblade7d40d812018-09-30 02:44:01 -070080 0xF9, 0xC0, 0x00, // -2
81 0x04,
82 0xF9, 0x7E, 0x00, // qNaN
83 0x05,
84 0xF9, 0x7C, 0x01, // sNaN
85 0x06,
86 0xF9, 0x7E, 0x0F, // qNaN with payload 0x0f
87 0x07,
88 0xF9, 0x7C, 0x0F, // sNaN with payload 0x0f
89
Laurence Lundblade68a13352018-09-23 02:19:54 -070090};
91
92
Laurence Lundbladebb474be2018-10-22 11:53:21 +053093int HalfPrecisionDecodeBasicTests()
Laurence Lundblade68a13352018-09-23 02:19:54 -070094{
Laurence Lundbladebb474be2018-10-22 11:53:21 +053095 UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf);
Laurence Lundblade68a13352018-09-23 02:19:54 -070096
97 QCBORDecodeContext DC;
98 QCBORDecode_Init(&DC, HalfPrecision, 0);
99
100 QCBORItem Item;
101
102 QCBORDecode_GetNext(&DC, &Item);
103 if(Item.uDataType != QCBOR_TYPE_MAP) {
104 return -1;
105 }
106
107 QCBORDecode_GetNext(&DC, &Item);
108 if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 0.0F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700109 return -2;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700110 }
111
112 QCBORDecode_GetNext(&DC, &Item);
113 if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != INFINITY) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700114 return -3;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700115 }
116
117 QCBORDecode_GetNext(&DC, &Item);
118 if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != -INFINITY) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700119 return -4;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700120 }
121
122 QCBORDecode_GetNext(&DC, &Item); // TODO, is this really converting right? It is carrying payload, but this confuses things.
123 if(Item.uDataType != QCBOR_TYPE_FLOAT || !isnan(Item.val.fnum)) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700124 return -5;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700125 }
126
127 QCBORDecode_GetNext(&DC, &Item);
128 if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 1.0F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700129 return -6;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700130 }
131
132 QCBORDecode_GetNext(&DC, &Item);
133 if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 0.333251953125F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700134 return -7;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700135 }
136
137 QCBORDecode_GetNext(&DC, &Item);
138 if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 65504.0F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700139 return -8;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700140 }
141
142 QCBORDecode_GetNext(&DC, &Item);
143 if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != INFINITY) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700144 return -9;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700145 }
146
147 QCBORDecode_GetNext(&DC, &Item); // TODO: check this
148 if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 0.0000000596046448F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700149 return -10;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700150 }
151
152 QCBORDecode_GetNext(&DC, &Item); // TODO: check this
153 if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 0.0000609755516F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700154 return -11;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700155 }
156
157 QCBORDecode_GetNext(&DC, &Item); // TODO check this
158 if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 0.0000610351563F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700159 return -12;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700160 }
161
162 QCBORDecode_GetNext(&DC, &Item);
163 if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 0) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700164 return -13;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700165 }
166
167 QCBORDecode_GetNext(&DC, &Item);
168 if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != -2.0F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700169 return -14;
170 }
171
172 QCBORDecode_GetNext(&DC, &Item);
173 if(Item.uDataType != QCBOR_TYPE_FLOAT || UsefulBufUtil_CopyFloatToUint32(Item.val.fnum) != 0x7fc00000L) {
174 return -15;
175 }
176 QCBORDecode_GetNext(&DC, &Item);
177 if(Item.uDataType != QCBOR_TYPE_FLOAT || UsefulBufUtil_CopyFloatToUint32(Item.val.fnum) != 0x7f800001) {
178 return -16;
179 }
180 QCBORDecode_GetNext(&DC, &Item);
181 if(Item.uDataType != QCBOR_TYPE_FLOAT || UsefulBufUtil_CopyFloatToUint32(Item.val.fnum) != 0x7fc0000f) {
182 return -17;
183 }
184 QCBORDecode_GetNext(&DC, &Item);
185 if(Item.uDataType != QCBOR_TYPE_FLOAT || UsefulBufUtil_CopyFloatToUint32(Item.val.fnum) != 0x7f80000f) {
186 return -18;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700187 }
188
189 if(QCBORDecode_Finish(&DC)) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700190 return -19;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700191 }
192
193 return 0;
194}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700195
196
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700197
198
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530199int HalfPrecisionAgainstRFCCodeTest()
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700200{
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700201 for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700202 unsigned char x[2];
203 x[1] = uHalfP & 0xff;
204 x[0] = uHalfP >> 8;
205 double d = decode_half(x);
206
207 // Contruct the CBOR for the half-precision float by hand
Laurence Lundblade4fe9f312018-10-22 10:22:39 +0530208 UsefulBuf_MAKE_STACK_UB(__xx, 3);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700209 UsefulOutBuf UOB;
210 UsefulOutBuf_Init(&UOB, __xx);
211
212 const uint8_t uHalfPrecInitialByte = HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5); // 0xf9
213 UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float
214 UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP);
215
216 // Now parse the hand-constructed CBOR. This will invoke the conversion to a float
217 QCBORDecodeContext DC;
218 QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
219
220 QCBORItem Item;
221
222 QCBORDecode_GetNext(&DC, &Item);
223 if(Item.uDataType != QCBOR_TYPE_FLOAT) {
224 return -1;
225 }
226
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700227 //printf("%04x QCBOR:%15.15f RFC: %15.15f (%8x)\n", uHalfP,Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d));
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700228
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700229 if(isnan(d)) {
230 // The RFC code uses the native instructions which may or may not
231 // handle sNaN, qNaN and NaN payloads correctly. This test just
232 // makes sure it is a NaN and doesn't worry about the type of NaN
233 if(!isnan(Item.val.fnum)) {
234 return -3;
235 }
236 } else {
237 if(Item.val.fnum != d) {
238 return -2;
239 }
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700240 }
241 }
242 return 0;
243}
244
245
246/*
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530247 {"zero": 0.0,
248 "negative zero": -0.0,
249 "infinitity": Infinity,
250 "negative infinitity": -Infinity,
251 "NaN": NaN,
252 "one": 1.0,
253 "one third": 0.333251953125,
254 "largest half-precision": 65504.0,
255 "largest half-precision point one": 65504.1,
256 "too-large half-precision": 65536.0,
257 "smallest subnormal": 5.96046448e-8,
258 "smallest normal": 0.00006103515261202119,
259 "biggest subnormal": 0.00006103515625,
260 "subnormal single": 4.00000646641519e-40,
261 3: -2.0,
262 "large single exp": 2.5521177519070385e+38,
263 "too-large single exp": 5.104235503814077e+38,
264 "biggest single with prec": 16777216.0,
265 "first single with prec loss": 16777217.0,
266 1: "fin"}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700267 */
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530268static const uint8_t spExpectedSmallest[] = {
269 0xB4, 0x64, 0x7A, 0x65, 0x72, 0x6F, 0xF9, 0x00, 0x00, 0x6D,
270 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x7A,
271 0x65, 0x72, 0x6F, 0xF9, 0x80, 0x00, 0x6A, 0x69, 0x6E, 0x66,
272 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, 0xF9, 0x7C, 0x00,
273 0x73, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20,
274 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
275 0xF9, 0xFC, 0x00, 0x63, 0x4E, 0x61, 0x4E, 0xF9, 0x7E, 0x00,
276 0x63, 0x6F, 0x6E, 0x65, 0xF9, 0x3C, 0x00, 0x69, 0x6F, 0x6E,
277 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, 0xF9, 0x35, 0x55,
278 0x76, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68,
279 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73,
280 0x69, 0x6F, 0x6E, 0xF9, 0x7B, 0xFF, 0x78, 0x20, 0x6C, 0x61,
281 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66,
282 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
283 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x65,
284 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33, 0x78,
285 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65,
286 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63,
287 0x69, 0x73, 0x69, 0x6F, 0x6E, 0xFA, 0x47, 0x80, 0x00, 0x00,
288 0x72, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20,
289 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xFB,
290 0x3E, 0x70, 0x00, 0x00, 0x00, 0x1C, 0x5F, 0x68, 0x6F, 0x73,
291 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F,
292 0x72, 0x6D, 0x61, 0x6C, 0xFA, 0x38, 0x7F, 0xFF, 0xFF, 0x71,
293 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75,
294 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xF9, 0x04, 0x00,
295 0x70, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
296 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0xFB, 0x37, 0xC1,
297 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF9, 0xC0, 0x00,
298 0x70, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E,
299 0x67, 0x6C, 0x65, 0x20, 0x65, 0x78, 0x70, 0xFA, 0x7F, 0x40,
300 0x00, 0x00, 0x74, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72,
301 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
302 0x65, 0x78, 0x70, 0xFB, 0x47, 0xF8, 0x00, 0x00, 0x00, 0x00,
303 0x00, 0x00, 0x78, 0x18, 0x62, 0x69, 0x67, 0x67, 0x65, 0x73,
304 0x74, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77,
305 0x69, 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0xFA, 0x4B,
306 0x80, 0x00, 0x00, 0x78, 0x1B, 0x66, 0x69, 0x72, 0x73, 0x74,
307 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, 0x69,
308 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x20, 0x6C, 0x6F,
309 0x73, 0x73, 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00,
310 0x00, 0x01, 0x63, 0x66, 0x69, 0x6E
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700311};
312
313
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530314int DoubleAsSmallestTest()
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700315{
Laurence Lundblade4fe9f312018-10-22 10:22:39 +0530316 UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, 420);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700317
318 QCBOREncodeContext EC;
319 QCBOREncode_Init(&EC, EncodedHalfsMem);
320 // These are mostly from https://en.wikipedia.org/wiki/Half-precision_floating-point_format
321 QCBOREncode_OpenMap(&EC);
322 // 64 # text(4)
323 // 7A65726F # "zero"
324 // F9 0000 # primitive(0)
325 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "zero", 0.00);
326
327 // 64 # text(4)
328 // 7A65726F # "negative zero"
329 // F9 8000 # primitive(0)
330 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative zero", -0.00);
331
332 // 6A # text(10)
333 // 696E66696E6974697479 # "infinitity"
334 // F9 7C00 # primitive(31744)
335 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "infinitity", INFINITY);
336
337 // 73 # text(19)
338 // 6E6567617469766520696E66696E6974697479 # "negative infinitity"
339 // F9 FC00 # primitive(64512)
340 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative infinitity", -INFINITY);
341
342 // 63 # text(3)
343 // 4E614E # "NaN"
344 // F9 7E00 # primitive(32256)
345 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "NaN", NAN);
346
347 // TODO: test a few NaN variants
348
349 // 63 # text(3)
350 // 6F6E65 # "one"
351 // F9 3C00 # primitive(15360)
352 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one", 1.0);
353
354 // 69 # text(9)
355 // 6F6E65207468697264 # "one third"
356 // F9 3555 # primitive(13653)
357 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one third", 0.333251953125);
358
359 // 76 # text(22)
360 // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
361 // F9 7BFF # primitive(31743)
362 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision",65504.0);
363
364 // 76 # text(22)
365 // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
366 // F9 7BFF # primitive(31743)
367 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision point one",65504.1);
368
369 // Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which is larger than 15, the largest half-precision exponent
370 // 78 18 # text(24)
371 // 746F6F2D6C617267652068616C662D707265636973696F6E # "too-large half-precision"
372 // FA 47800000 # primitive(31743)
373 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large half-precision", 65536.0);
374
375 // The smallest possible half-precision subnormal, but digitis are lost converting
376 // to half, so this turns into a double
377 // 72 # text(18)
378 // 736D616C6C657374207375626E6F726D616C # "smallest subnormal"
379 // FB 3E700000001C5F68 # primitive(4499096027744984936)
380 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest subnormal", 0.0000000596046448);
381
382 // The smallest possible half-precision snormal, but digitis are lost converting
383 // to half, so this turns into a single TODO: confirm this is right
384 // 6F # text(15)
385 // 736D616C6C657374206E6F726D616C # "smallest normal"
386 // FA 387FFFFF # primitive(947912703)
387 // in hex single is 0x387fffff, exponent -15, significand 7fffff
388 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest normal", 0.0000610351526F);
389
390 // 71 # text(17)
391 // 62696767657374207375626E6F726D616C # "biggest subnormal"
392 // F9 0400 # primitive(1024)
393 // in hex single is 0x38800000, exponent -14, significand 0
394 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest subnormal", 0.0000610351563F);
395
396 // 70 # text(16)
397 // 7375626E6F726D616C2073696E676C65 # "subnormal single"
398 // FB 37C16C2800000000 # primitive(4017611261645684736)
399 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "subnormal single", 4e-40F);
400
401 // 03 # unsigned(3)
402 // F9 C000 # primitive(49152)
403 QCBOREncode_AddDoubleAsSmallestToMapN(&EC, 3, -2.0);
404
405 // 70 # text(16)
406 // 6C617267652073696E676C6520657870 # "large single exp"
407 // FA 7F400000 # primitive(2134900736)
408 // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((127LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT);
409 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "large single exp", 2.5521177519070385E+38); // Exponent fits single
410
411 // 74 # text(20)
412 // 746F6F2D6C617267652073696E676C6520657870 # "too-large single exp"
413 // FB 47F8000000000000 # primitive(5185894970917126144)
414 // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((128LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT);
415 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large single exp", 5.104235503814077E+38); // Exponent too large for single
416
417 // 66 # text(6)
418 // 646664666465 # "dfdfde"
419 // FA 4B800000 # primitive(1266679808)
420 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest single with prec",16777216); // Single with no precision loss
421
422 // 78 18 # text(24)
423 // 626967676573742073696E676C6520776974682070726563 # "biggest single with prec"
424 // FA 4B800000 # primitive(1266679808)
425 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "first single with prec loss",16777217); // Double becuase of precision loss
426
427 // Just a convenient marker when cutting and pasting encoded CBOR
428 QCBOREncode_AddSZStringToMapN(&EC, 1, "fin");
429
430 QCBOREncode_CloseMap(&EC);
431
Laurence Lundblade781fd822018-10-01 09:37:52 -0700432 UsefulBufC EncodedHalfs;
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700433 int nReturn = QCBOREncode_Finish2(&EC, &EncodedHalfs);
434 if(nReturn) {
435 return -1;
436 }
437
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530438 if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700439 return -3;
440 }
441
442 return 0;
Laurence Lundblade570fab52018-10-13 18:28:27 +0800443}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700444
445
446
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700447#ifdef NAN_EXPERIMENT
448/*
449 Code for checking what the double to float cast does with
450 NaNs. Not run as part of tests. Keep it around to
451 be able to check various platforms and CPUs.
452 */
453
454#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
455#define DOUBLE_NUM_EXPONENT_BITS (11)
456#define DOUBLE_NUM_SIGN_BITS (1)
457
458#define DOUBLE_SIGNIFICAND_SHIFT (0)
459#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS)
460#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
461
462#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits
463#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
464#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
465#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
466
467
468static int NaNExperiments() {
469 double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
470 double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
471 double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
472
473 float f1 = (float)dqNaN;
474 float f2 = (float)dsNaN;
475 float f3 = (float)dqNaNPayload;
476
477
478 uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
479 uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
480 uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
481
482 // Result of this on x86 is that every NaN is a qNaN. The intel
483 // CVTSD2SS instruction ignores the NaN payload and even converts
484 // a sNaN to a qNaN.
485
486 return 0;
487}
488#endif
489
490
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700491