blob: 20057c32fbaabf7e7f8fb94f8fe16badeea0fefd [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 Lundblade2d85ce42018-10-12 14:12:47 +080013#include "float_tests.h"
Laurence Lundblade68a13352018-09-23 02:19:54 -070014#include "qcbor.h"
Laurence Lundbladed711fb22018-09-26 14:35:22 -070015#include "half_to_double_from_rfc7049.h"
16#include <math.h> // For INFINITY and NAN and isnan()
Laurence Lundblade68a13352018-09-23 02:19:54 -070017
Laurence Lundblade2d85ce42018-10-12 14:12:47 +080018
Laurence Lundblade2d85ce42018-10-12 14:12:47 +080019
Laurence Lundbladebb474be2018-10-22 11:53:21 +053020static const uint8_t spExpectedHalf[] = {
Laurence Lundblade7d40d812018-09-30 02:44:01 -070021 0xB1,
Laurence Lundblade68a13352018-09-23 02:19:54 -070022 0x64,
23 0x7A, 0x65, 0x72, 0x6F,
24 0xF9, 0x00, 0x00, // 0.000
25 0x6A,
26 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
27 0xF9, 0x7C, 0x00, // Infinity
28 0x73,
Laurence Lundbladeee851742020-01-08 08:37:05 -080029 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E,
30 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
Laurence Lundblade68a13352018-09-23 02:19:54 -070031 0xF9, 0xFC, 0x00, // -Inifinity
32 0x63,
33 0x4E, 0x61, 0x4E,
34 0xF9, 0x7E, 0x00, // NaN
35 0x63,
36 0x6F, 0x6E, 0x65,
37 0xF9, 0x3C, 0x00, // 1.0
38 0x69,
39 0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64,
40 0xF9, 0x35, 0x55, // 0.333251953125
41 0x76,
Laurence Lundbladeee851742020-01-08 08:37:05 -080042 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C,
43 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
Laurence Lundblade68a13352018-09-23 02:19:54 -070044 0xF9, 0x7B, 0xFF, // 65504.0
Laurence Lundbladeee851742020-01-08 08:37:05 -080045 0x78, 0x18,
46 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x68,
47 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69,
48 0x6F, 0x6E,
Laurence Lundblade68a13352018-09-23 02:19:54 -070049 0xF9, 0x7C, 0x00, // Infinity
50 0x72,
Laurence Lundbladeee851742020-01-08 08:37:05 -080051 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75,
52 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
Laurence Lundblade68a13352018-09-23 02:19:54 -070053 0xF9, 0x00, 0x01, // 0.000000059604
54 0x6F,
Laurence Lundbladeee851742020-01-08 08:37:05 -080055 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F,
56 0x72, 0x6D, 0x61, 0x6C,
Laurence Lundblade68a13352018-09-23 02:19:54 -070057 0xF9, 0x03, 0xFF, // 0.0000609755516
58 0x71,
Laurence Lundbladeee851742020-01-08 08:37:05 -080059 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62,
60 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
Laurence Lundblade68a13352018-09-23 02:19:54 -070061 0xF9, 0x04, 0x00, // 0.000061988
62 0x70,
Laurence Lundbladeee851742020-01-08 08:37:05 -080063 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73,
64 0x69, 0x6E, 0x67, 0x6C, 0x65,
Laurence Lundblade68a13352018-09-23 02:19:54 -070065 0xF9, 0x00, 0x00,
66 0x03,
Laurence Lundblade7d40d812018-09-30 02:44:01 -070067 0xF9, 0xC0, 0x00, // -2
68 0x04,
69 0xF9, 0x7E, 0x00, // qNaN
70 0x05,
71 0xF9, 0x7C, 0x01, // sNaN
72 0x06,
73 0xF9, 0x7E, 0x0F, // qNaN with payload 0x0f
74 0x07,
75 0xF9, 0x7C, 0x0F, // sNaN with payload 0x0f
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080076
Laurence Lundblade68a13352018-09-23 02:19:54 -070077};
78
79
Laurence Lundbladec5fef682020-01-25 11:38:45 -080080int32_t HalfPrecisionDecodeBasicTests()
Laurence Lundblade68a13352018-09-23 02:19:54 -070081{
Laurence Lundbladebb474be2018-10-22 11:53:21 +053082 UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080083
Laurence Lundblade68a13352018-09-23 02:19:54 -070084 QCBORDecodeContext DC;
85 QCBORDecode_Init(&DC, HalfPrecision, 0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080086
Laurence Lundblade68a13352018-09-23 02:19:54 -070087 QCBORItem Item;
88
89 QCBORDecode_GetNext(&DC, &Item);
90 if(Item.uDataType != QCBOR_TYPE_MAP) {
91 return -1;
92 }
93
94 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +070095 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -070096 return -2;
Laurence Lundblade68a13352018-09-23 02:19:54 -070097 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -080098
Laurence Lundblade68a13352018-09-23 02:19:54 -070099 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700100 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700101 return -3;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700102 }
103
104 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700105 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -INFINITY) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700106 return -4;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700107 }
108
Laurence Lundbladeee851742020-01-08 08:37:05 -0800109 // TODO, is this really converting right? It is carrying payload, but
110 // this confuses things.
111 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700112 if(Item.uDataType != QCBOR_TYPE_DOUBLE || !isnan(Item.val.dfnum)) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700113 return -5;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700114 }
115
116 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700117 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 1.0F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700118 return -6;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700119 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800120
Laurence Lundblade68a13352018-09-23 02:19:54 -0700121 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700122 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.333251953125F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700123 return -7;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700124 }
125
126 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700127 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 65504.0F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700128 return -8;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700129 }
130
131 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700132 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700133 return -9;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700134 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800135
Laurence Lundblade68a13352018-09-23 02:19:54 -0700136 QCBORDecode_GetNext(&DC, &Item); // TODO: check this
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700137 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000000596046448F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700138 return -10;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700139 }
140
141 QCBORDecode_GetNext(&DC, &Item); // TODO: check this
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700142 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000609755516F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700143 return -11;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700144 }
145
146 QCBORDecode_GetNext(&DC, &Item); // TODO check this
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700147 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000610351563F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700148 return -12;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700149 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800150
151 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700152 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700153 return -13;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700154 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800155
Laurence Lundblade68a13352018-09-23 02:19:54 -0700156 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700157 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -2.0F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700158 return -14;
159 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800160
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700161 // TODO: double check these four tests
162 QCBORDecode_GetNext(&DC, &Item); // qNaN
Laurence Lundbladeee851742020-01-08 08:37:05 -0800163 if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
164 UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff8000000000000ULL) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700165 return -15;
166 }
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700167 QCBORDecode_GetNext(&DC, &Item); // sNaN
Laurence Lundbladeee851742020-01-08 08:37:05 -0800168 if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
169 UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff0000000000001ULL) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700170 return -16;
171 }
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700172 QCBORDecode_GetNext(&DC, &Item); // qNaN with payload 0x0f
Laurence Lundbladeee851742020-01-08 08:37:05 -0800173 if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
174 UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff800000000000fULL) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700175 return -17;
176 }
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700177 QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f
Laurence Lundbladeee851742020-01-08 08:37:05 -0800178 if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
179 UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff000000000000fULL) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700180 return -18;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700181 }
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700182
Laurence Lundblade68a13352018-09-23 02:19:54 -0700183 if(QCBORDecode_Finish(&DC)) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700184 return -19;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700185 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800186
Laurence Lundblade68a13352018-09-23 02:19:54 -0700187 return 0;
188}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700189
190
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700191
192
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800193int32_t HalfPrecisionAgainstRFCCodeTest()
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700194{
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700195 for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700196 unsigned char x[2];
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800197 x[1] = (uint8_t)(uHalfP & 0xff);
198 x[0] = (uint8_t)(uHalfP >> 8); // uHalfP is always less than 0xffff
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700199 double d = decode_half(x);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800200
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700201 // Contruct the CBOR for the half-precision float by hand
Laurence Lundblade4fe9f312018-10-22 10:22:39 +0530202 UsefulBuf_MAKE_STACK_UB(__xx, 3);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700203 UsefulOutBuf UOB;
204 UsefulOutBuf_Init(&UOB, __xx);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800205
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800206 const uint8_t uHalfPrecInitialByte = (uint8_t)(HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5)); // 0xf9
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700207 UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float
208 UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP);
209
Laurence Lundbladeee851742020-01-08 08:37:05 -0800210 // Now parse the hand-constructed CBOR. This will invoke the
211 // conversion to a float
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700212 QCBORDecodeContext DC;
213 QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800214
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700215 QCBORItem Item;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800216
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700217 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700218 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700219 return -1;
220 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800221
Laurence Lundbladeee851742020-01-08 08:37:05 -0800222 //printf("%04x QCBOR:%15.15f RFC: %15.15f (%8x)\n",
223 // uHalfP, Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d));
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800224
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700225 if(isnan(d)) {
226 // The RFC code uses the native instructions which may or may not
227 // handle sNaN, qNaN and NaN payloads correctly. This test just
228 // makes sure it is a NaN and doesn't worry about the type of NaN
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700229 if(!isnan(Item.val.dfnum)) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700230 return -3;
231 }
232 } else {
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700233 if(Item.val.dfnum != d) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700234 return -2;
235 }
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700236 }
237 }
238 return 0;
239}
240
241
242/*
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530243 {"zero": 0.0,
244 "negative zero": -0.0,
245 "infinitity": Infinity,
246 "negative infinitity": -Infinity,
247 "NaN": NaN,
248 "one": 1.0,
249 "one third": 0.333251953125,
250 "largest half-precision": 65504.0,
251 "largest half-precision point one": 65504.1,
252 "too-large half-precision": 65536.0,
253 "smallest subnormal": 5.96046448e-8,
254 "smallest normal": 0.00006103515261202119,
255 "biggest subnormal": 0.00006103515625,
256 "subnormal single": 4.00000646641519e-40,
257 3: -2.0,
258 "large single exp": 2.5521177519070385e+38,
259 "too-large single exp": 5.104235503814077e+38,
260 "biggest single with prec": 16777216.0,
261 "first single with prec loss": 16777217.0,
262 1: "fin"}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700263 */
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530264static const uint8_t spExpectedSmallest[] = {
265 0xB4, 0x64, 0x7A, 0x65, 0x72, 0x6F, 0xF9, 0x00, 0x00, 0x6D,
266 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x7A,
267 0x65, 0x72, 0x6F, 0xF9, 0x80, 0x00, 0x6A, 0x69, 0x6E, 0x66,
268 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, 0xF9, 0x7C, 0x00,
269 0x73, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20,
270 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
271 0xF9, 0xFC, 0x00, 0x63, 0x4E, 0x61, 0x4E, 0xF9, 0x7E, 0x00,
272 0x63, 0x6F, 0x6E, 0x65, 0xF9, 0x3C, 0x00, 0x69, 0x6F, 0x6E,
273 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, 0xF9, 0x35, 0x55,
274 0x76, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68,
275 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73,
276 0x69, 0x6F, 0x6E, 0xF9, 0x7B, 0xFF, 0x78, 0x20, 0x6C, 0x61,
277 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66,
278 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
279 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x65,
280 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33, 0x78,
281 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65,
282 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63,
283 0x69, 0x73, 0x69, 0x6F, 0x6E, 0xFA, 0x47, 0x80, 0x00, 0x00,
284 0x72, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20,
285 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xFB,
286 0x3E, 0x70, 0x00, 0x00, 0x00, 0x1C, 0x5F, 0x68, 0x6F, 0x73,
287 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F,
288 0x72, 0x6D, 0x61, 0x6C, 0xFA, 0x38, 0x7F, 0xFF, 0xFF, 0x71,
289 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75,
290 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xF9, 0x04, 0x00,
291 0x70, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
292 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0xFB, 0x37, 0xC1,
293 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF9, 0xC0, 0x00,
294 0x70, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E,
295 0x67, 0x6C, 0x65, 0x20, 0x65, 0x78, 0x70, 0xFA, 0x7F, 0x40,
296 0x00, 0x00, 0x74, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72,
297 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
298 0x65, 0x78, 0x70, 0xFB, 0x47, 0xF8, 0x00, 0x00, 0x00, 0x00,
299 0x00, 0x00, 0x78, 0x18, 0x62, 0x69, 0x67, 0x67, 0x65, 0x73,
300 0x74, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77,
301 0x69, 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0xFA, 0x4B,
302 0x80, 0x00, 0x00, 0x78, 0x1B, 0x66, 0x69, 0x72, 0x73, 0x74,
303 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, 0x69,
304 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x20, 0x6C, 0x6F,
305 0x73, 0x73, 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00,
306 0x00, 0x01, 0x63, 0x66, 0x69, 0x6E
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700307};
308
309
Laurence Lundbladec5fef682020-01-25 11:38:45 -0800310int32_t DoubleAsSmallestTest()
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700311{
Laurence Lundblade4fe9f312018-10-22 10:22:39 +0530312 UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, 420);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800313
Laurence Lundblade067035b2018-11-28 17:35:25 -0800314#define QCBOREncode_AddDoubleAsSmallestToMap QCBOREncode_AddDoubleToMap
315#define QCBOREncode_AddDoubleAsSmallestToMapN QCBOREncode_AddDoubleToMapN
316
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800317
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700318 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);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800331
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700332 // 6A # text(10)
333 // 696E66696E6974697479 # "infinitity"
334 // F9 7C00 # primitive(31744)
335 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "infinitity", INFINITY);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800336
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700337 // 73 # text(19)
338 // 6E6567617469766520696E66696E6974697479 # "negative infinitity"
339 // F9 FC00 # primitive(64512)
340 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative infinitity", -INFINITY);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800341
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700342 // 63 # text(3)
343 // 4E614E # "NaN"
344 // F9 7E00 # primitive(32256)
345 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "NaN", NAN);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800346
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700347 // TODO: test a few NaN variants
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800348
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700349 // 63 # text(3)
350 // 6F6E65 # "one"
351 // F9 3C00 # primitive(15360)
352 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one", 1.0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800353
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700354 // 69 # text(9)
355 // 6F6E65207468697264 # "one third"
356 // F9 3555 # primitive(13653)
357 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one third", 0.333251953125);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800358
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700359 // 76 # text(22)
Laurence Lundbladeee851742020-01-08 08:37:05 -0800360 // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700361 // F9 7BFF # primitive(31743)
362 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision",65504.0);
363
364 // 76 # text(22)
Laurence Lundbladeee851742020-01-08 08:37:05 -0800365 // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700366 // F9 7BFF # primitive(31743)
367 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision point one",65504.1);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800368
Laurence Lundbladeee851742020-01-08 08:37:05 -0800369 // Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which
370 // is larger than 15, the largest half-precision exponent
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700371 // 78 18 # text(24)
372 // 746F6F2D6C617267652068616C662D707265636973696F6E # "too-large half-precision"
373 // FA 47800000 # primitive(31743)
374 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large half-precision", 65536.0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800375
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700376 // The smallest possible half-precision subnormal, but digitis are lost converting
377 // to half, so this turns into a double
378 // 72 # text(18)
379 // 736D616C6C657374207375626E6F726D616C # "smallest subnormal"
380 // FB 3E700000001C5F68 # primitive(4499096027744984936)
381 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest subnormal", 0.0000000596046448);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800382
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700383 // The smallest possible half-precision snormal, but digitis are lost converting
384 // to half, so this turns into a single TODO: confirm this is right
385 // 6F # text(15)
386 // 736D616C6C657374206E6F726D616C # "smallest normal"
387 // FA 387FFFFF # primitive(947912703)
388 // in hex single is 0x387fffff, exponent -15, significand 7fffff
389 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest normal", 0.0000610351526F);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800390
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700391 // 71 # text(17)
392 // 62696767657374207375626E6F726D616C # "biggest subnormal"
393 // F9 0400 # primitive(1024)
394 // in hex single is 0x38800000, exponent -14, significand 0
395 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest subnormal", 0.0000610351563F);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800396
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700397 // 70 # text(16)
398 // 7375626E6F726D616C2073696E676C65 # "subnormal single"
399 // FB 37C16C2800000000 # primitive(4017611261645684736)
400 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "subnormal single", 4e-40F);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800401
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700402 // 03 # unsigned(3)
403 // F9 C000 # primitive(49152)
404 QCBOREncode_AddDoubleAsSmallestToMapN(&EC, 3, -2.0);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800405
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700406 // 70 # text(16)
407 // 6C617267652073696E676C6520657870 # "large single exp"
408 // FA 7F400000 # primitive(2134900736)
409 // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((127LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT);
410 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "large single exp", 2.5521177519070385E+38); // Exponent fits single
411
412 // 74 # text(20)
413 // 746F6F2D6C617267652073696E676C6520657870 # "too-large single exp"
414 // FB 47F8000000000000 # primitive(5185894970917126144)
415 // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((128LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT);
Laurence Lundbladeee851742020-01-08 08:37:05 -0800416 // Exponent too large for single
417 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large single exp", 5.104235503814077E+38);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700418
419 // 66 # text(6)
420 // 646664666465 # "dfdfde"
421 // FA 4B800000 # primitive(1266679808)
Laurence Lundbladeee851742020-01-08 08:37:05 -0800422 // Single with no precision loss
423 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest single with prec", 16777216);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800424
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700425 // 78 18 # text(24)
426 // 626967676573742073696E676C6520776974682070726563 # "biggest single with prec"
427 // FA 4B800000 # primitive(1266679808)
Laurence Lundbladeee851742020-01-08 08:37:05 -0800428 // Double becuase of precision loss
429 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "first single with prec loss", 16777217);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800430
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700431 // Just a convenient marker when cutting and pasting encoded CBOR
432 QCBOREncode_AddSZStringToMapN(&EC, 1, "fin");
433
434 QCBOREncode_CloseMap(&EC);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800435
Laurence Lundblade781fd822018-10-01 09:37:52 -0700436 UsefulBufC EncodedHalfs;
Laurence Lundblade0595e932018-11-02 22:22:47 +0700437 int nReturn = QCBOREncode_Finish(&EC, &EncodedHalfs);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700438 if(nReturn) {
439 return -1;
440 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800441
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530442 if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700443 return -3;
444 }
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800445
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700446 return 0;
Laurence Lundblade570fab52018-10-13 18:28:27 +0800447}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700448
449
450
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700451#ifdef NAN_EXPERIMENT
452/*
453 Code for checking what the double to float cast does with
454 NaNs. Not run as part of tests. Keep it around to
455 be able to check various platforms and CPUs.
456 */
457
458#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
459#define DOUBLE_NUM_EXPONENT_BITS (11)
460#define DOUBLE_NUM_SIGN_BITS (1)
461
462#define DOUBLE_SIGNIFICAND_SHIFT (0)
463#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS)
464#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
465
466#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits
467#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
468#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
469#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
470
471
472static int NaNExperiments() {
473 double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
474 double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
475 double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800476
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700477 float f1 = (float)dqNaN;
478 float f2 = (float)dsNaN;
479 float f3 = (float)dqNaNPayload;
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800480
481
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700482 uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
483 uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
484 uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800485
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700486 // Result of this on x86 is that every NaN is a qNaN. The intel
487 // CVTSD2SS instruction ignores the NaN payload and even converts
488 // a sNaN to a qNaN.
Laurence Lundblade3aee3a32018-12-17 16:17:45 -0800489
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700490 return 0;
491}
492#endif
493
494
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700495