big improvement to preferred serialization tests; variable name tweak
diff --git a/test/float_tests.c b/test/float_tests.c
index 8886ab8..a66ef04 100644
--- a/test/float_tests.c
+++ b/test/float_tests.c
@@ -21,8 +21,9 @@
#include "half_to_double_from_rfc7049.h"
-// A series of half precision values to test half-precision decoding
/*
+ Half-precision values that are input to test half-precision decoding
+
As decoded by http://cbor.me
{"zero": 0.0,
"infinitity": Infinity,
@@ -101,6 +102,12 @@
};
+inline static bool CheckDouble(double d, uint64_t u)
+{
+ return UsefulBufUtil_CopyDoubleToUint64(d) != u;
+}
+
+
int32_t HalfPrecisionDecodeBasicTests()
{
UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf);
@@ -130,8 +137,8 @@
return -4;
}
- // TODO: NAN-related is this really converting right? It is carrying payload, but
- // this confuses things.
+ // TODO: NAN-related is this really converting right? It is carrying
+ // payload, but this confuses things.
QCBORDecode_GetNext(&DC, &Item);
if(Item.uDataType != QCBOR_TYPE_DOUBLE || !isnan(Item.val.dfnum)) {
return -5;
@@ -192,22 +199,22 @@
// TODO: NAN-related double check these four tests
QCBORDecode_GetNext(&DC, &Item); // qNaN
if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
- UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff8000000000000ULL) {
+ CheckDouble(Item.val.dfnum, 0x7ff8000000000000ULL)) {
return -15;
}
QCBORDecode_GetNext(&DC, &Item); // sNaN
if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
- UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff0000000000001ULL) {
+ CheckDouble(Item.val.dfnum, 0x7ff0000000000001ULL)) {
return -16;
}
QCBORDecode_GetNext(&DC, &Item); // qNaN with payload 0x0f
if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
- UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff800000000000fULL) {
+ CheckDouble(Item.val.dfnum, 0x7ff800000000000fULL)) {
return -17;
}
QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f
if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
- UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff000000000000fULL) {
+ CheckDouble(Item.val.dfnum, 0x7ff000000000000fULL)) {
return -18;
}
@@ -271,209 +278,279 @@
/*
- {"zero": 0.0,
- "negative zero": -0.0,
- "infinitity": Infinity,
- "negative infinitity": -Infinity,
- "NaN": NaN,
- "one": 1.0,
- "one third": 0.333251953125,
- "largest half-precision": 65504.0,
- "largest half-precision point one": 65504.1,
- "too-large half-precision": 65536.0,
- "smallest subnormal": 5.96046448e-8,
- "smallest normal": 0.00006103515261202119,
- "biggest subnormal": 0.00006103515625,
- "subnormal single": 4.00000646641519e-40,
- 3: -2.0,
- "large single exp": 2.5521177519070385e+38,
- "too-large single exp": 5.104235503814077e+38,
- "biggest single with prec": 16777216.0,
- "first single with prec loss": 16777217.0,
- 1: "fin"}
+ Expected output from preferred serialization of some of floating-point numbers
+{"zero": 0.0,
+ "negative zero": -0.0,
+ "infinitity": Infinity,
+ "negative infinitity": -Infinity,
+ "NaN": NaN,
+ "one": 1.0,
+ "one third": 0.333251953125,
+ "largest half-precision": 65504.0,
+ "largest half-precision point one": 65504.1,
+ "too-large half-precision": 65536.0,
+ "smallest half subnormal": 5.960464477539063e-8,
+ "smallest half normal": 0.00006103515625,
+ "smallest half normal plus": 0.00006103515625000001,
+ "smallest normal minus": 0.000030517578125,
+ "largest single": 3.4028234663852886e+38,
+ "largest single plus": 6.805646932770577e+38,
+ "smallest single": 1.1754943508222875e-38,
+ "smallest single plus": 1.1754943508222878e-38,
+ "smallest single minus": 1.1754943508222874e-38,
+ "smallest single minus more": 5.877471754111438e-39,
+ 3: -2.0, "single precision": 16777216.0,
+ "single with precision loss": 16777217.0,
+ 1: "fin"}
*/
+// TODO: check these values in hex against expected encoded by hand
static const uint8_t spExpectedSmallest[] = {
- 0xB4, 0x64, 0x7A, 0x65, 0x72, 0x6F, 0xF9, 0x00, 0x00, 0x6D,
- 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x7A,
- 0x65, 0x72, 0x6F, 0xF9, 0x80, 0x00, 0x6A, 0x69, 0x6E, 0x66,
- 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, 0xF9, 0x7C, 0x00,
- 0x73, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20,
- 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
- 0xF9, 0xFC, 0x00, 0x63, 0x4E, 0x61, 0x4E, 0xF9, 0x7E, 0x00,
- 0x63, 0x6F, 0x6E, 0x65, 0xF9, 0x3C, 0x00, 0x69, 0x6F, 0x6E,
- 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, 0xF9, 0x35, 0x55,
- 0x76, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68,
- 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73,
- 0x69, 0x6F, 0x6E, 0xF9, 0x7B, 0xFF, 0x78, 0x20, 0x6C, 0x61,
- 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66,
- 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E,
- 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x6F, 0x6E, 0x65,
- 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33, 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, 0xFA, 0x47, 0x80, 0x00, 0x00,
- 0x72, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20,
- 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xFB,
- 0x3E, 0x70, 0x00, 0x00, 0x00, 0x1C, 0x5F, 0x68, 0x6F, 0x73,
- 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F,
- 0x72, 0x6D, 0x61, 0x6C, 0xFA, 0x38, 0x7F, 0xFF, 0xFF, 0x71,
- 0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75,
- 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xF9, 0x04, 0x00,
- 0x70, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
- 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0xFB, 0x37, 0xC1,
- 0x6C, 0x28, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF9, 0xC0, 0x00,
- 0x70, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E,
- 0x67, 0x6C, 0x65, 0x20, 0x65, 0x78, 0x70, 0xFA, 0x7F, 0x40,
- 0x00, 0x00, 0x74, 0x74, 0x6F, 0x6F, 0x2D, 0x6C, 0x61, 0x72,
- 0x67, 0x65, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
- 0x65, 0x78, 0x70, 0xFB, 0x47, 0xF8, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x78, 0x18, 0x62, 0x69, 0x67, 0x67, 0x65, 0x73,
- 0x74, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77,
- 0x69, 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0xFA, 0x4B,
- 0x80, 0x00, 0x00, 0x78, 0x1B, 0x66, 0x69, 0x72, 0x73, 0x74,
- 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x77, 0x69,
- 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x20, 0x6C, 0x6F,
- 0x73, 0x73, 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00,
- 0x00, 0x01, 0x63, 0x66, 0x69, 0x6E
+ 0xB8, 0x1A, 0x64, 0x7A, 0x65, 0x72, 0x6F, 0xF9, 0x00, 0x00,
+ 0x6D, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20,
+ 0x7A, 0x65, 0x72, 0x6F, 0xF9, 0x80, 0x00, 0x6A, 0x69, 0x6E,
+ 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79, 0xF9, 0x7C,
+ 0x00, 0x73, 0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65,
+ 0x20, 0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74,
+ 0x79, 0xF9, 0xFC, 0x00, 0x63, 0x4E, 0x61, 0x4E, 0xF9, 0x7E,
+ 0x00, 0x63, 0x6F, 0x6E, 0x65, 0xF9, 0x3C, 0x00, 0x69, 0x6F,
+ 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64, 0xF9, 0x35,
+ 0x55, 0x76, 0x6C, 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20,
+ 0x68, 0x61, 0x6C, 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69,
+ 0x73, 0x69, 0x6F, 0x6E, 0xF9, 0x7B, 0xFF, 0x78, 0x20, 0x6C,
+ 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C,
+ 0x66, 0x2D, 0x70, 0x72, 0x65, 0x63, 0x69, 0x73, 0x69, 0x6F,
+ 0x6E, 0x20, 0x70, 0x6F, 0x69, 0x6E, 0x74, 0x20, 0x6F, 0x6E,
+ 0x65, 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33,
+ 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, 0xFA, 0x47, 0x80, 0x00,
+ 0x00, 0x77, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74,
+ 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20, 0x73, 0x75, 0x62, 0x6E,
+ 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0xFA, 0x33, 0x80, 0x00, 0x00,
+ 0x74, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20,
+ 0x68, 0x61, 0x6C, 0x66, 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61,
+ 0x6C, 0xF9, 0x04, 0x00, 0x78, 0x19, 0x73, 0x6D, 0x61, 0x6C,
+ 0x6C, 0x65, 0x73, 0x74, 0x20, 0x68, 0x61, 0x6C, 0x66, 0x20,
+ 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x70, 0x6C, 0x75,
+ 0x73, 0xFB, 0x3F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+ 0x75, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20,
+ 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x6D, 0x69, 0x6E,
+ 0x75, 0x73, 0xFB, 0x3F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0x75, 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74,
+ 0x20, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x6D, 0x69,
+ 0x6E, 0x75, 0x73, 0xFA, 0x38, 0x00, 0x00, 0x00, 0x6E, 0x6C,
+ 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, 0x6E,
+ 0x67, 0x6C, 0x65, 0xFA, 0x7F, 0x7F, 0xFF, 0xFF, 0x73, 0x6C,
+ 0x61, 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, 0x6E,
+ 0x67, 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x75, 0x73, 0xFB, 0x47,
+ 0xEF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01, 0x73, 0x6C, 0x61,
+ 0x72, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, 0x6E, 0x67,
+ 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x75, 0x73, 0xFB, 0x47, 0xFF,
+ 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x6F, 0x73, 0x6D, 0x61,
+ 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, 0x6E, 0x67,
+ 0x6C, 0x65, 0xFA, 0x00, 0x80, 0x00, 0x00, 0x74, 0x73, 0x6D,
+ 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, 0x6E,
+ 0x67, 0x6C, 0x65, 0x20, 0x70, 0x6C, 0x75, 0x73, 0xFB, 0x38,
+ 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x75, 0x73, 0x6D,
+ 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x69, 0x6E,
+ 0x67, 0x6C, 0x65, 0x20, 0x6D, 0x69, 0x6E, 0x75, 0x73, 0xFB,
+ 0x38, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x78, 0x1A,
+ 0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73,
+ 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x6D, 0x69, 0x6E, 0x75,
+ 0x73, 0x20, 0x6D, 0x6F, 0x72, 0x65, 0xFB, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xF9, 0xC0, 0x00, 0x70,
+ 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20, 0x70, 0x72, 0x65,
+ 0x63, 0x69, 0x73, 0x69, 0x6F, 0x6E, 0xFA, 0x4B, 0x80, 0x00,
+ 0x00, 0x78, 0x1A, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65, 0x20,
+ 0x77, 0x69, 0x74, 0x68, 0x20, 0x70, 0x72, 0x65, 0x63, 0x69,
+ 0x73, 0x69, 0x6F, 0x6E, 0x20, 0x6C, 0x6F, 0x73, 0x73, 0xFB,
+ 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x01, 0x63,
+ 0x66, 0x69, 0x6E
};
+/*
+ Makes a double from a uint64_t by copying the bits, not
+ by converting the value.
+ */
+#define MAKE_DOUBLE(x) UsefulBufUtil_CopyUint64ToDouble(x)
+
+
int32_t DoubleAsSmallestTest()
{
- UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, 420);
+ UsefulBuf_MAKE_STACK_UB(EncodedHalfsMem, sizeof(spExpectedSmallest));
-#define QCBOREncode_AddDoubleToMap QCBOREncode_AddDoubleToMap
+ QCBOREncodeContext EC;
+ QCBOREncode_Init(&EC, EncodedHalfsMem);
+ QCBOREncode_OpenMap(&EC);
+ // Many of these are from
+ // https://en.wikipedia.org/wiki/Half-precision_floating-point_format
+ // and
+ // https://en.wikipedia.org/wiki/Single-precision_floating-point_format
- QCBOREncodeContext EC;
- QCBOREncode_Init(&EC, EncodedHalfsMem);
- // These are mostly from https://en.wikipedia.org/wiki/Half-precision_floating-point_format
- QCBOREncode_OpenMap(&EC);
- // 64 # text(4)
- // 7A65726F # "zero"
- // F9 0000 # primitive(0)
- QCBOREncode_AddDoubleToMap(&EC, "zero", 0.00);
+ // 64 # text(4)
+ // 7A65726F # "zero"
+ // F9 0000 # primitive(0)
+ QCBOREncode_AddDoubleToMap(&EC, "zero", 0.00);
- // 64 # text(4)
- // 7A65726F # "negative zero"
- // F9 8000 # primitive(0)
- QCBOREncode_AddDoubleToMap(&EC, "negative zero", -0.00);
+ // 64 # text(4)
+ // 7A65726F # "negative zero"
+ // F9 8000 # primitive(0)
+ QCBOREncode_AddDoubleToMap(&EC, "negative zero", -0.00);
- // 6A # text(10)
- // 696E66696E6974697479 # "infinitity"
- // F9 7C00 # primitive(31744)
- QCBOREncode_AddDoubleToMap(&EC, "infinitity", INFINITY);
+ // 6A # text(10)
+ // 696E66696E6974697479 # "infinitity"
+ // F9 7C00 # primitive(31744)
+ QCBOREncode_AddDoubleToMap(&EC, "infinitity", INFINITY);
- // 73 # text(19)
- // 6E6567617469766520696E66696E6974697479 # "negative infinitity"
- // F9 FC00 # primitive(64512)
- QCBOREncode_AddDoubleToMap(&EC, "negative infinitity", -INFINITY);
+ // 73 # text(19)
+ // 6E6567617469766520696E66696E6974697479 # "negative infinitity"
+ // F9 FC00 # primitive(64512)
+ QCBOREncode_AddDoubleToMap(&EC, "negative infinitity", -INFINITY);
- // 63 # text(3)
- // 4E614E # "NaN"
- // F9 7E00 # primitive(32256)
- QCBOREncode_AddDoubleToMap(&EC, "NaN", NAN);
+ // 63 # text(3)
+ // 4E614E # "NaN"
+ // F9 7E00 # primitive(32256)
+ QCBOREncode_AddDoubleToMap(&EC, "NaN", NAN);
- // TODO: test a few NaN variants
+ // TODO: test a few NaN variants
- // 63 # text(3)
- // 6F6E65 # "one"
- // F9 3C00 # primitive(15360)
- QCBOREncode_AddDoubleToMap(&EC, "one", 1.0);
+ // 63 # text(3)
+ // 6F6E65 # "one"
+ // F9 3C00 # primitive(15360)
+ QCBOREncode_AddDoubleToMap(&EC, "one", 1.0);
- // 69 # text(9)
- // 6F6E65207468697264 # "one third"
- // F9 3555 # primitive(13653)
- QCBOREncode_AddDoubleToMap(&EC, "one third", 0.333251953125);
+ // 69 # text(9)
+ // 6F6E65207468697264 # "one third"
+ // F9 3555 # primitive(13653)
+ QCBOREncode_AddDoubleToMap(&EC, "one third", 0.333251953125);
- // 76 # text(22)
- // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
- // F9 7BFF # primitive(31743)
- QCBOREncode_AddDoubleToMap(&EC, "largest half-precision",65504.0);
+ // 65504.0, converts to the large possible half-precision.
+ QCBOREncode_AddDoubleToMap(&EC, "largest half-precision", 65504.0);
- // 76 # text(22)
- // 6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
- // F9 7BFF # primitive(31743)
- QCBOREncode_AddDoubleToMap(&EC, "largest half-precision point one",65504.1);
+ // 65504.1, the double that has both to large an exponent and too
+ // much precision, so no conversion.
+ QCBOREncode_AddDoubleToMap(&EC, "largest half-precision point one", 65504.1);
- // Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which
- // is larger than 15, the largest half-precision exponent
- // 78 18 # text(24)
- // 746F6F2D6C617267652068616C662D707265636973696F6E # "too-large half-precision"
- // FA 47800000 # primitive(31743)
- QCBOREncode_AddDoubleToMap(&EC, "too-large half-precision", 65536.0);
+ // 65536.0 has an exponent of 16, which is larger than 15, the
+ // largest half-precision exponent. It is the exponent, not
+ // precision loss that prevents conversion to half. It does convert
+ // to single precision.
+ QCBOREncode_AddDoubleToMap(&EC, "too-large half-precision", 65536.0);
- // The smallest possible half-precision subnormal, but digitis are lost converting
- // to half, so this turns into a double
- // 72 # text(18)
- // 736D616C6C657374207375626E6F726D616C # "smallest subnormal"
- // FB 3E700000001C5F68 # primitive(4499096027744984936)
- QCBOREncode_AddDoubleToMap(&EC, "smallest subnormal", 0.0000000596046448);
+ // 5.9604644775390625E-8, the smallest possible half-precision
+ // subnormal, but digitis are lost converting to half, so this is
+ // output as a double.
+ QCBOREncode_AddDoubleToMap(&EC,
+ "smallest half subnormal",
+ MAKE_DOUBLE(0x3e70000000000000));
- // The smallest possible half-precision snormal, but digitis are lost converting
- // to half, so this turns into a single TODO: confirm this is right
- // 6F # text(15)
- // 736D616C6C657374206E6F726D616C # "smallest normal"
- // FA 387FFFFF # primitive(947912703)
- // in hex single is 0x387fffff, exponent -15, significand 7fffff
- QCBOREncode_AddDoubleToMap(&EC, "smallest normal", 0.0000610351526F);
+ // 0.00006103515625, the double value that converts to the smallest
+ // possible half-precision normal. which is what should appear in
+ // the output.
+ QCBOREncode_AddDoubleToMap(&EC,
+ "smallest half normal",
+ MAKE_DOUBLE(0x3f10000000000000));
- // 71 # text(17)
- // 62696767657374207375626E6F726D616C # "biggest subnormal"
- // F9 0400 # primitive(1024)
- // in hex single is 0x38800000, exponent -14, significand 0
- QCBOREncode_AddDoubleToMap(&EC, "biggest subnormal", 0.0000610351563F);
+ // 0.000061035156250000014 ,the double value that is a tiny bit
+ // greater than smallest possible half-precision normal. It will be
+ // output as a double because converting it will reduce precision.
+ QCBOREncode_AddDoubleToMap(&EC,
+ "smallest half normal plus",
+ MAKE_DOUBLE(0x3f10000000000001));
- // 70 # text(16)
- // 7375626E6F726D616C2073696E676C65 # "subnormal single"
- // FB 37C16C2800000000 # primitive(4017611261645684736)
- QCBOREncode_AddDoubleToMap(&EC, "subnormal single", 4e-40F);
+ // 0.000061035156249999993, the double value that is a tiny bit
+ // smaller than the smallest half-precision normal. This will fail
+ // to convert to a half-precision because both the exponent is too
+ // small and the precision is too large for a half-precision.
+ QCBOREncode_AddDoubleToMap(&EC,
+ "smallest normal minus",
+ MAKE_DOUBLE(0x3f0fffffffffffff));
- // 03 # unsigned(3)
- // F9 C000 # primitive(49152)
- QCBOREncode_AddDoubleToMapN(&EC, 3, -2.0);
+ // 0.000030517578125, the double value that is too small to fit
+ // into a half-precision because the exponent won't fit, not
+ // because precision would be lost. (This would fit into a
+ // half-precision subnormal, but there is no converstion to
+ // that). This ends up encoded as a single-precision.
+ QCBOREncode_AddDoubleToMap(&EC,
+ "smallest normal minus",
+ MAKE_DOUBLE(0x3f00000000000000));
- // 70 # text(16)
- // 6C617267652073696E676C6520657870 # "large single exp"
- // FA 7F400000 # primitive(2134900736)
- // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((127LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT);
- QCBOREncode_AddDoubleToMap(&EC, "large single exp", 2.5521177519070385E+38); // Exponent fits single
+ // 3.4028234664e38, the value that converts to the largest possible
+ // single-precision.
+ QCBOREncode_AddDoubleToMap(&EC,
+ "largest single",
+ MAKE_DOUBLE(0x47efffffe0000000));
- // 74 # text(20)
- // 746F6F2D6C617267652073696E676C6520657870 # "too-large single exp"
- // FB 47F8000000000000 # primitive(5185894970917126144)
- // (0x01LL << (DOUBLE_NUM_SIGNIFICAND_BITS-1)) | ((128LL + DOUBLE_EXPONENT_BIAS) << DOUBLE_EXPONENT_SHIFT);
- // Exponent too large for single
- QCBOREncode_AddDoubleToMap(&EC, "too-large single exp", 5.104235503814077E+38);
+ // 3.402823466385289E38, sightly larger than the largest possible
+ // possible precision. Conversion fails because precision would be
+ // lost.
+ QCBOREncode_AddDoubleToMap(&EC,
+ "largest single plus",
+ MAKE_DOUBLE(0x47efffffe0000001));
- // 66 # text(6)
- // 646664666465 # "dfdfde"
- // FA 4B800000 # primitive(1266679808)
- // Single with no precision loss
- QCBOREncode_AddDoubleToMap(&EC, "biggest single with prec", 16777216);
+ // 6.8056469327705772E38, slightly more larger than the largers
+ // possible single precision. Conversion fails because exponent is
+ // too large.
+ QCBOREncode_AddDoubleToMap(&EC,
+ "largest single plus",
+ MAKE_DOUBLE(0x47ffffffe0000000));
- // 78 18 # text(24)
- // 626967676573742073696E676C6520776974682070726563 # "biggest single with prec"
- // FA 4B800000 # primitive(1266679808)
- // Double becuase of precision loss
- QCBOREncode_AddDoubleToMap(&EC, "first single with prec loss", 16777217);
+ // 1.1754943508222875E-38, The double value that converts to the
+ // smallest possible single-precision normal
+ QCBOREncode_AddDoubleToMap(&EC,
+ "smallest single",
+ MAKE_DOUBLE(0x3810000000000000));
- // Just a convenient marker when cutting and pasting encoded CBOR
- QCBOREncode_AddSZStringToMapN(&EC, 1, "fin");
+ // 1.1754943508222878E-38, double value that is slightly larger
+ // than the smallest single-precision normal. Conversion fails
+ // because of precision
+ QCBOREncode_AddDoubleToMap(&EC,
+ "smallest single plus",
+ MAKE_DOUBLE(0x3810000000000001));
- QCBOREncode_CloseMap(&EC);
+ // 1.1754943508222874E-38, slightly smaller than the smallest
+ // single-precision normal. Conversion fails because of precsiion
+ QCBOREncode_AddDoubleToMap(&EC,
+ "smallest single minus",
+ MAKE_DOUBLE(0x380fffffffffffff));
- UsefulBufC EncodedHalfs;
- QCBORError uErr = QCBOREncode_Finish(&EC, &EncodedHalfs);
- if(uErr) {
- return -1;
- }
+ // 5.8774717541114375E-39, slightly smaller than the smallest
+ // single-precision normal. Conversion fails because the exponent
+ // is too small.
+ QCBOREncode_AddDoubleToMap(&EC,
+ "smallest single minus more",
+ MAKE_DOUBLE(0x3800000000000000));
- if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) {
- return -3;
- }
+ // Just -2, which converts to a negative half-precision
+ // F9 C000 # primitive(49152)
+ QCBOREncode_AddDoubleToMapN(&EC, 3, -2.0);
- return 0;
+ // 16777216, No precision loss converting to single
+ // FA 4B800000 # primitive(1266679808)
+ QCBOREncode_AddDoubleToMap(&EC, "single precision", 16777216);
+
+ // 16777217, One more than above. Too much precision for a single
+ // so no conversion.
+ QCBOREncode_AddDoubleToMap(&EC, "single with precision loss", 16777217);
+
+ // Just a convenient marker when cutting and pasting encoded CBOR
+ QCBOREncode_AddSZStringToMapN(&EC, 1, "fin");
+
+ QCBOREncode_CloseMap(&EC);
+
+ UsefulBufC EncodedHalfs;
+ QCBORError uErr = QCBOREncode_Finish(&EC, &EncodedHalfs);
+ if(uErr) {
+ return -1;
+ }
+
+ if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) {
+ return -3;
+ }
+
+ return 0;
}
#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
@@ -545,13 +622,14 @@
int32_t GeneralFloatEncodeTests()
{
+ UsefulBufC ExpectedFloats;
#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloats));
- UsefulBufC ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
+ ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
(void)spExpectedFloatsNoHalf; // Avoid unused variable error
#else
UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloatsNoHalf));
- UsefulBufC ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloatsNoHalf);
+ ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloatsNoHalf);
(void)spExpectedFloats; // Avoid unused variable error
#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */