blob: 091dc5c90ffe61845225fd3aca30482ed33b4162 [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);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700108 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 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);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700113 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 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);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700118 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -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.
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700123 if(Item.uDataType != QCBOR_TYPE_DOUBLE || !isnan(Item.val.dfnum)) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700124 return -5;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700125 }
126
127 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700128 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 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);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700133 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 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);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700138 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 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);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700143 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 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
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700148 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 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
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700153 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 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
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700158 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 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);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700163 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 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);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700168 if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -2.0F) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700169 return -14;
170 }
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700171
172 // TODO: double check these four tests
173 QCBORDecode_GetNext(&DC, &Item); // qNaN
174 if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff8000000000000ULL) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700175 return -15;
176 }
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700177 QCBORDecode_GetNext(&DC, &Item); // sNaN
178 if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff0000000000001ULL) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700179 return -16;
180 }
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700181 QCBORDecode_GetNext(&DC, &Item); // qNaN with payload 0x0f
182 if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff800000000000fULL) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700183 return -17;
184 }
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700185 QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f
186 if(Item.uDataType != QCBOR_TYPE_DOUBLE || UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff000000000000fULL) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700187 return -18;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700188 }
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700189
Laurence Lundblade68a13352018-09-23 02:19:54 -0700190 if(QCBORDecode_Finish(&DC)) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700191 return -19;
Laurence Lundblade68a13352018-09-23 02:19:54 -0700192 }
193
194 return 0;
195}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700196
197
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700198
199
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530200int HalfPrecisionAgainstRFCCodeTest()
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700201{
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700202 for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700203 unsigned char x[2];
204 x[1] = uHalfP & 0xff;
205 x[0] = uHalfP >> 8;
206 double d = decode_half(x);
207
208 // Contruct the CBOR for the half-precision float by hand
Laurence Lundblade4fe9f312018-10-22 10:22:39 +0530209 UsefulBuf_MAKE_STACK_UB(__xx, 3);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700210 UsefulOutBuf UOB;
211 UsefulOutBuf_Init(&UOB, __xx);
212
213 const uint8_t uHalfPrecInitialByte = HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5); // 0xf9
214 UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float
215 UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP);
216
217 // Now parse the hand-constructed CBOR. This will invoke the conversion to a float
218 QCBORDecodeContext DC;
219 QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
220
221 QCBORItem Item;
222
223 QCBORDecode_GetNext(&DC, &Item);
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700224 if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700225 return -1;
226 }
227
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700228 //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 -0700229
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700230 if(isnan(d)) {
231 // The RFC code uses the native instructions which may or may not
232 // handle sNaN, qNaN and NaN payloads correctly. This test just
233 // makes sure it is a NaN and doesn't worry about the type of NaN
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700234 if(!isnan(Item.val.dfnum)) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700235 return -3;
236 }
237 } else {
Laurence Lundblade67bd5512018-11-02 21:44:06 +0700238 if(Item.val.dfnum != d) {
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700239 return -2;
240 }
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700241 }
242 }
243 return 0;
244}
245
246
247/*
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530248 {"zero": 0.0,
249 "negative zero": -0.0,
250 "infinitity": Infinity,
251 "negative infinitity": -Infinity,
252 "NaN": NaN,
253 "one": 1.0,
254 "one third": 0.333251953125,
255 "largest half-precision": 65504.0,
256 "largest half-precision point one": 65504.1,
257 "too-large half-precision": 65536.0,
258 "smallest subnormal": 5.96046448e-8,
259 "smallest normal": 0.00006103515261202119,
260 "biggest subnormal": 0.00006103515625,
261 "subnormal single": 4.00000646641519e-40,
262 3: -2.0,
263 "large single exp": 2.5521177519070385e+38,
264 "too-large single exp": 5.104235503814077e+38,
265 "biggest single with prec": 16777216.0,
266 "first single with prec loss": 16777217.0,
267 1: "fin"}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700268 */
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530269static const uint8_t spExpectedSmallest[] = {
270 0xB4, 0x64, 0x7A, 0x65, 0x72, 0x6F, 0xF9, 0x00, 0x00, 0x6D,
271 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x7A,
272 0x65, 0x72, 0x6F, 0xF9, 0x80, 0x00, 0x6A, 0x69, 0x6E, 0x66,
273 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, 0xF9, 0x7C, 0x00,
274 0x73, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20,
275 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
276 0xF9, 0xFC, 0x00, 0x63, 0x4E, 0x61, 0x4E, 0xF9, 0x7E, 0x00,
277 0x63, 0x6F, 0x6E, 0x65, 0xF9, 0x3C, 0x00, 0x69, 0x6F, 0x6E,
278 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, 0xF9, 0x35, 0x55,
279 0x76, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68,
280 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73,
281 0x69, 0x6F, 0x6E, 0xF9, 0x7B, 0xFF, 0x78, 0x20, 0x6C, 0x61,
282 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66,
283 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
284 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x65,
285 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33, 0x78,
286 0x18, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72, 0x67, 0x65,
287 0x20, 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63,
288 0x69, 0x73, 0x69, 0x6F, 0x6E, 0xFA, 0x47, 0x80, 0x00, 0x00,
289 0x72, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20,
290 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xFB,
291 0x3E, 0x70, 0x00, 0x00, 0x00, 0x1C, 0x5F, 0x68, 0x6F, 0x73,
292 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F,
293 0x72, 0x6D, 0x61, 0x6C, 0xFA, 0x38, 0x7F, 0xFF, 0xFF, 0x71,
294 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75,
295 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xF9, 0x04, 0x00,
296 0x70, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
297 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0xFB, 0x37, 0xC1,
298 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF9, 0xC0, 0x00,
299 0x70, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E,
300 0x67, 0x6C, 0x65, 0x20, 0x65, 0x78, 0x70, 0xFA, 0x7F, 0x40,
301 0x00, 0x00, 0x74, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72,
302 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
303 0x65, 0x78, 0x70, 0xFB, 0x47, 0xF8, 0x00, 0x00, 0x00, 0x00,
304 0x00, 0x00, 0x78, 0x18, 0x62, 0x69, 0x67, 0x67, 0x65, 0x73,
305 0x74, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77,
306 0x69, 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0xFA, 0x4B,
307 0x80, 0x00, 0x00, 0x78, 0x1B, 0x66, 0x69, 0x72, 0x73, 0x74,
308 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, 0x69,
309 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x20, 0x6C, 0x6F,
310 0x73, 0x73, 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00,
311 0x00, 0x01, 0x63, 0x66, 0x69, 0x6E
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700312};
313
314
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530315int DoubleAsSmallestTest()
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700316{
Laurence Lundblade4fe9f312018-10-22 10:22:39 +0530317 UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, 420);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700318
319 QCBOREncodeContext EC;
320 QCBOREncode_Init(&EC, EncodedHalfsMem);
321 // These are mostly from https://en.wikipedia.org/wiki/Half-precision_floating-point_format
322 QCBOREncode_OpenMap(&EC);
323 // 64 # text(4)
324 // 7A65726F # "zero"
325 // F9 0000 # primitive(0)
326 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "zero", 0.00);
327
328 // 64 # text(4)
329 // 7A65726F # "negative zero"
330 // F9 8000 # primitive(0)
331 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative zero", -0.00);
332
333 // 6A # text(10)
334 // 696E66696E6974697479 # "infinitity"
335 // F9 7C00 # primitive(31744)
336 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "infinitity", INFINITY);
337
338 // 73 # text(19)
339 // 6E6567617469766520696E66696E6974697479 # "negative infinitity"
340 // F9 FC00 # primitive(64512)
341 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative infinitity", -INFINITY);
342
343 // 63 # text(3)
344 // 4E614E # "NaN"
345 // F9 7E00 # primitive(32256)
346 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "NaN", NAN);
347
348 // TODO: test a few NaN variants
349
350 // 63 # text(3)
351 // 6F6E65 # "one"
352 // F9 3C00 # primitive(15360)
353 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one", 1.0);
354
355 // 69 # text(9)
356 // 6F6E65207468697264 # "one third"
357 // F9 3555 # primitive(13653)
358 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one third", 0.333251953125);
359
360 // 76 # text(22)
361 // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
362 // F9 7BFF # primitive(31743)
363 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision",65504.0);
364
365 // 76 # text(22)
366 // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
367 // F9 7BFF # primitive(31743)
368 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision point one",65504.1);
369
370 // Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which is larger than 15, the largest half-precision exponent
371 // 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);
375
376 // 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);
382
383 // 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);
390
391 // 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);
396
397 // 70 # text(16)
398 // 7375626E6F726D616C2073696E676C65 # "subnormal single"
399 // FB 37C16C2800000000 # primitive(4017611261645684736)
400 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "subnormal single", 4e-40F);
401
402 // 03 # unsigned(3)
403 // F9 C000 # primitive(49152)
404 QCBOREncode_AddDoubleAsSmallestToMapN(&EC, 3, -2.0);
405
406 // 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);
416 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large single exp", 5.104235503814077E+38); // Exponent too large for single
417
418 // 66 # text(6)
419 // 646664666465 # "dfdfde"
420 // FA 4B800000 # primitive(1266679808)
421 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest single with prec",16777216); // Single with no precision loss
422
423 // 78 18 # text(24)
424 // 626967676573742073696E676C6520776974682070726563 # "biggest single with prec"
425 // FA 4B800000 # primitive(1266679808)
426 QCBOREncode_AddDoubleAsSmallestToMap(&EC, "first single with prec loss",16777217); // Double becuase of precision loss
427
428 // Just a convenient marker when cutting and pasting encoded CBOR
429 QCBOREncode_AddSZStringToMapN(&EC, 1, "fin");
430
431 QCBOREncode_CloseMap(&EC);
432
Laurence Lundblade781fd822018-10-01 09:37:52 -0700433 UsefulBufC EncodedHalfs;
Laurence Lundblade0595e932018-11-02 22:22:47 +0700434 int nReturn = QCBOREncode_Finish(&EC, &EncodedHalfs);
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700435 if(nReturn) {
436 return -1;
437 }
438
Laurence Lundbladebb474be2018-10-22 11:53:21 +0530439 if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) {
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700440 return -3;
441 }
442
443 return 0;
Laurence Lundblade570fab52018-10-13 18:28:27 +0800444}
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700445
446
447
Laurence Lundblade7d40d812018-09-30 02:44:01 -0700448#ifdef NAN_EXPERIMENT
449/*
450 Code for checking what the double to float cast does with
451 NaNs. Not run as part of tests. Keep it around to
452 be able to check various platforms and CPUs.
453 */
454
455#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
456#define DOUBLE_NUM_EXPONENT_BITS (11)
457#define DOUBLE_NUM_SIGN_BITS (1)
458
459#define DOUBLE_SIGNIFICAND_SHIFT (0)
460#define DOUBLE_EXPONENT_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS)
461#define DOUBLE_SIGN_SHIFT (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
462
463#define DOUBLE_SIGNIFICAND_MASK (0xfffffffffffffULL) // The lower 52 bits
464#define DOUBLE_EXPONENT_MASK (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
465#define DOUBLE_SIGN_MASK (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
466#define DOUBLE_QUIET_NAN_BIT (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
467
468
469static int NaNExperiments() {
470 double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
471 double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
472 double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
473
474 float f1 = (float)dqNaN;
475 float f2 = (float)dsNaN;
476 float f3 = (float)dqNaNPayload;
477
478
479 uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
480 uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
481 uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
482
483 // Result of this on x86 is that every NaN is a qNaN. The intel
484 // CVTSD2SS instruction ignores the NaN payload and even converts
485 // a sNaN to a qNaN.
486
487 return 0;
488}
489#endif
490
491
Laurence Lundbladed711fb22018-09-26 14:35:22 -0700492