NaN payload bug fix; restructure some of the floating-point processing and disabling

This fixes a bug NaN payload preferred serialization where silent NaNs with payloads were incorrectly converted to quiet NaNs on some CPUs. Internal single-to-double conversions are now implemented in SW rather than using CPU.

Previously single-to-double conversion was disabled with QCBOR_DISABLE_FLOAT_HW_USE. Now it is disabled with QCBOR_DISABLE_PREFERRED_FLOAT. This is a behavior change and the reason the minor version number is incremented.

This also fixes a few error codes related to disabled floating-point features.

This updates the documentation on floating-point feature disabling.

Test coverage of floating-point is improved a lot, particularly for NaN payloads. Floating-point tests are refactored to be more clear and organized. Test against Carsten's (partial) SW library is added.

QCBOR_ERR_HALF_PRECISION_DISABLED is renamed to QCBOR_ERR_PREFERRED_FLOAT_DISABLED to be more accurate. The old name it retained for backwards compatibility.

Left over redundant declaration of QCBOREncode_AddBytes() and some others was removed.

Error out when using AddDouble() and AddFloat() in dCBOR mode with QCBOR_DISABLE_PREFFERED_FLOAT since it won't be able to produce correct dCBOR.

Some reduction in code size for single-precision decoding.

Corrected error codes for the various floating-point disable #defines


* Improve test coverage of NaNs

* Correct NaN payload decoding with SW; NaN test coverage

* NaN Payload Revision

* #ifdef fanout should work

* Fan out works; some rearranging of code in file

* Adjust test cases for floats that now succeed without HW

* Fixes so ifdef fanout works

* Lots more testing...

* Lots of documentation and other fixes

* Missed a file

* Size optimization; more tests ...

* Fix nits

* Correct some error codes

* more test cases; code tidy

* Improve code structure for float decode

---------

Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/test/float_tests.c b/test/float_tests.c
index d36ef61..302b328 100644
--- a/test/float_tests.c
+++ b/test/float_tests.c
@@ -1,7 +1,7 @@
 /* ==========================================================================
  * float_tests.c -- tests for float and conversion to/from half-precision
  *
- * Copyright (c) 2018-2024, Laurence Lundblade. All rights reserved.
+ * Copyright (c) 2018-2025, Laurence Lundblade. All rights reserved.
  * Copyright (c) 2021, Arm Limited. All rights reserved.
  *
  * SPDX-License-Identifier: BSD-3-Clause
@@ -18,9 +18,16 @@
 #include "qcbor/qcbor_decode.h"
 #include "qcbor/qcbor_spiffy_decode.h"
 #include "qcbor/qcbor_number_decode.h"
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
 #include <math.h> /* For INFINITY and NAN and isnan() */
+#endif
 
 
+/* This is off because it is affected by varying behavior of CPUs,
+ * compilers and float libraries. Particularly the qNaN bit
+ */
+//#define QCBOR_COMPARE_TO_HW_CONVERSION
+
 
 /* Make a test results code that includes three components. Return code
  * is xxxyyyzzz where zz is the error code, yy is the test number and
@@ -38,14 +45,261 @@
 }
 
 
-#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
-
 #include "half_to_double_from_rfc7049.h"
 
 
+#ifndef USEFULBUF_DISABLE_ALL_FLOAT
+
+
+/* ----- Half Precsion ----------- */
+#define HALF_NUM_SIGNIFICAND_BITS (10)
+#define HALF_NUM_EXPONENT_BITS    (5)
+#define HALF_NUM_SIGN_BITS        (1)
+
+#define HALF_SIGNIFICAND_SHIFT    (0)
+#define HALF_EXPONENT_SHIFT       (HALF_NUM_SIGNIFICAND_BITS)
+#define HALF_SIGN_SHIFT           (HALF_NUM_SIGNIFICAND_BITS + HALF_NUM_EXPONENT_BITS)
+
+#define HALF_SIGNIFICAND_MASK     (0x3ffU) // The lower 10 bits
+#define HALF_EXPONENT_MASK        (0x1fU << HALF_EXPONENT_SHIFT) // 0x7c00 5 bits of exponent
+#define HALF_SIGN_MASK            (0x01U << HALF_SIGN_SHIFT) // 0x8000 1 bit of sign
+#define HALF_QUIET_NAN_BIT        (0x01U << (HALF_NUM_SIGNIFICAND_BITS-1)) // 0x0200
+
+/* Biased    Biased    Unbiased   Use
+ *  0x00       0        -15       0 and subnormal
+ *  0x01       1        -14       Smallest normal exponent
+ *  0x1e      30         15       Largest normal exponent
+ *  0x1F      31         16       NaN and Infinity  */
+#define HALF_EXPONENT_BIAS        (15)
+#define HALF_EXPONENT_MAX         (HALF_EXPONENT_BIAS)    //  15 Unbiased
+#define HALF_EXPONENT_MIN         (-HALF_EXPONENT_BIAS+1) // -14 Unbiased
+#define HALF_EXPONENT_ZERO        (-HALF_EXPONENT_BIAS)   // -15 Unbiased
+#define HALF_EXPONENT_INF_OR_NAN  (HALF_EXPONENT_BIAS+1)  //  16 Unbiased
+
+
+/* ------ Single-Precision -------- */
+#define SINGLE_NUM_SIGNIFICAND_BITS (23)
+#define SINGLE_NUM_EXPONENT_BITS    (8)
+#define SINGLE_NUM_SIGN_BITS        (1)
+
+#define SINGLE_SIGNIFICAND_SHIFT    (0)
+#define SINGLE_EXPONENT_SHIFT       (SINGLE_NUM_SIGNIFICAND_BITS)
+#define SINGLE_SIGN_SHIFT           (SINGLE_NUM_SIGNIFICAND_BITS + SINGLE_NUM_EXPONENT_BITS)
+
+#define SINGLE_SIGNIFICAND_MASK     (0x7fffffU) // The lower 23 bits
+#define SINGLE_EXPONENT_MASK        (0xffU << SINGLE_EXPONENT_SHIFT) // 8 bits of exponent
+#define SINGLE_SIGN_MASK            (0x01U << SINGLE_SIGN_SHIFT) // 1 bit of sign
+#define SINGLE_QUIET_NAN_BIT        (0x01U << (SINGLE_NUM_SIGNIFICAND_BITS-1))
+
+/* Biased  Biased   Unbiased  Use
+ *  0x0000     0     -127      0 and subnormal
+ *  0x0001     1     -126      Smallest normal exponent
+ *  0x7f     127        0      1
+ *  0xfe     254      127      Largest normal exponent
+ *  0xff     255      128      NaN and Infinity  */
+#define SINGLE_EXPONENT_BIAS        (127)
+#define SINGLE_EXPONENT_MAX         (SINGLE_EXPONENT_BIAS)
+#define SINGLE_EXPONENT_MIN         (-SINGLE_EXPONENT_BIAS+1)
+#define SINGLE_EXPONENT_ZERO        (-SINGLE_EXPONENT_BIAS)
+#define SINGLE_EXPONENT_INF_OR_NAN  (SINGLE_EXPONENT_BIAS+1)
+
+#define SINGLE_NAN_BITS             SINGLE_EXPONENT_MASK /* NAN bits except payload */
+#define SINGLE_QNAN                 0x400000
+#define SINGLE_SNAN                 0x000000
+
+
+/* --------- Double-Precision ---------- */
+#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
+#define DOUBLE_NUM_EXPONENT_BITS    (11)
+#define DOUBLE_NUM_SIGN_BITS        (1)
+
+#define DOUBLE_SIGNIFICAND_SHIFT    (0)
+#define DOUBLE_EXPONENT_SHIFT       (DOUBLE_NUM_SIGNIFICAND_BITS)
+#define DOUBLE_SIGN_SHIFT           (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
+
+#define DOUBLE_SIGNIFICAND_MASK     (0xfffffffffffffULL) // The lower 52 bits
+#define DOUBLE_EXPONENT_MASK        (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
+#define DOUBLE_SIGN_MASK            (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
+#define DOUBLE_QUIET_NAN_BIT        (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
+
+
+/* Biased      Biased   Unbiased  Use
+ * 0x00000000     0     -1023     0 and subnormal
+ * 0x00000001     1     -1022     Smallest normal exponent
+ * 0x000007fe  2046      1023     Largest normal exponent
+ * 0x000007ff  2047      1024     NaN and Infinity  */
+#define DOUBLE_EXPONENT_BIAS        (1023)
+#define DOUBLE_EXPONENT_MAX         (DOUBLE_EXPONENT_BIAS)
+#define DOUBLE_EXPONENT_MIN         (-DOUBLE_EXPONENT_BIAS+1)
+#define DOUBLE_EXPONENT_ZERO        (-DOUBLE_EXPONENT_BIAS)
+#define DOUBLE_EXPONENT_INF_OR_NAN  (DOUBLE_EXPONENT_BIAS+1)
+
+#define DOUBLE_NAN_BITS             DOUBLE_EXPONENT_MASK /* NAN bits except payload */
+#define DOUBLE_QNAN                 0x8000000000000ULL
+#define DOUBLE_SNAN                 0x0000000000000ULL
+
+
+
+#ifdef NAN_EXPERIMENT
+#include <stdlib.h>
+#include <stdio.h>
+
+ int
+NaNExperiments(void)
+{
+   // double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
+   // double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
+   // double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
+
+
+   for(int i = 999; i < 1000; i++) {
+      uint64_t x1 = (uint64_t)rand() % SINGLE_SIGNIFICAND_MASK;
+
+      uint64_t uDub = DOUBLE_EXPONENT_MASK | (x1 << (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS));
+
+      double dd = UsefulBufUtil_CopyUint64ToDouble(uDub);
+
+      float ff = (float)dd;
+
+      uint32_t uu = UsefulBufUtil_CopyFloatToUint32(ff);
+
+      uint64_t x2 = uu & SINGLE_SIGNIFICAND_MASK;
+
+      if(x2 != x1) {
+         printf("%d: %llx %llx %llx %llx\n", i, x1, x2, x1 ^ x2, x1 & 0x200000);
+      }
+   }
+
+#if 0
+    float f1 = (float)dqNaN;
+    float f2 = (float)dsNaN;
+    float f3 = (float)dqNaNPayload;
+
+
+    uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
+    uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
+    uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
+
+    // Result of this on x86 is that every NaN is a qNaN. The intel
+    // CVTSD2SS instruction ignores the NaN payload and even converts
+    // a sNaN to a qNaN.
+#endif
+
+    return 0;
+}
+#endif /* NAN_EXPERIMENT */
+
+
+/* Returns 0 if OK, 1 if not */
+static int32_t
+HWCheckFloatToDouble(const uint64_t uDoubleToConvert, uint32_t uExpectedSingle)
+{
+#ifdef QCBOR_COMPARE_TO_HW_CONVERSION
+   if(uExpectedSingle) {
+      /* This test is off by default. It's purpose is to check
+       * QCBOR's mask-n-shift implementation against the HW/CPU
+       * instructions that do conversion between double and single.
+       * It is off because it is only used on occasion to verify
+       * QCBOR and because it is suspected that some HW/CPU does
+       * not implement this correctly. NaN payloads are an obscure
+       * feature. */
+      float    f;
+      double   d;
+      uint32_t uSingle;
+
+      d = UsefulBufUtil_CopyUint64ToDouble(uDoubleToConvert);
+
+      f = (float)d;
+
+      uSingle = UsefulBufUtil_CopyFloatToUint32(f);
+
+      if(isnan(d)) {
+         /* Some (all?) Intel CPUs always set the qNaN bit in conversion */
+         uExpectedSingle |= SINGLE_QNAN;
+      }
+
+      if(uSingle != uExpectedSingle) {
+         return 1;
+      }
+   }
+#else
+   (void)uDoubleToConvert;
+   (void)uExpectedSingle;
+#endif /* QCBOR_COMPARE_TO_HW_CONVERSION */
+
+   return 0;
+}
+
+/* Returns 0 if OK, 1 if not */
+static int32_t
+HWCheckDoubleToFloat(const uint32_t uSingleToConvert, uint64_t uExpectedDouble)
+{
+#ifdef QCBOR_COMPARE_TO_HW_CONVERSION
+   if(uExpectedDouble) {
+      /* This test is off by default. It's purpose is to check
+       * QCBOR's mask-n-shift implementation against the HW/CPU
+       * instructions that do conversion between double and single.
+       * It is off because it is only used on occasion to verify
+       * QCBOR and because it is suspected that some HW/CPU does
+       * not implement this correctly. NaN payloads are an obscure
+       * feature. */
+      float    f;
+      double   d2;
+      uint64_t dd;
+
+      f = UsefulBufUtil_CopyUint32ToFloat(uSingleToConvert);
+
+      d2 = (double)f;
+
+      dd = UsefulBufUtil_CopyDoubleToUint64(d2);
+
+      if(isnan(f)) {
+         /* Some (all?) Intel CPUs always set the qNaN bit in conversion */
+         uExpectedDouble |= DOUBLE_QNAN;
+      }
+
+      if(dd != uExpectedDouble ) {
+         return 1;
+      }
+   }
+#else
+   (void)uSingleToConvert;
+   (void)uExpectedDouble;
+#endif /* QCBOR_COMPARE_TO_HW_CONVERSION */
+   return 0;
+}
+
+
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+/* Returns 0 if OK, 1 if not */
+static int32_t
+CompareToCarsten(const uint64_t uDouble, const UsefulBufC TestOutput, const UsefulBufC Expected)
+{
+   if(Expected.len == 3) {
+      /* Just works for double to half now */
+      int uFloat16 = try_float16_encode(uDouble);
+      uint8_t CarstenEncoded[3];
+      CarstenEncoded[0] = 0xf9;
+      CarstenEncoded[1] = (uFloat16 & 0xff00) >> 8;
+      CarstenEncoded[2] = uFloat16 & 0xff;
+
+      UsefulBufC CarstenEncodedUB;
+      CarstenEncodedUB.len = 3;
+      CarstenEncodedUB.ptr = CarstenEncoded;
+
+      if(UsefulBuf_Compare(TestOutput, CarstenEncodedUB)) {
+         return 1;
+      }
+   }
+
+   return 0;
+}
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+
 struct FloatTestCase {
    double      dNumber;
-   float       fNumber;
+   float       fNumber; /* Only used when preferred is disabled  */
    UsefulBufC  Preferred;
    UsefulBufC  NotPreferred;
    UsefulBufC  CDE;
@@ -77,10 +331,14 @@
  */
 
 /* Always four lines per test case so shell scripts can process into
- * other formats. CDE and DCBOR standards are not complete yet,
- * encodings are what is expected.  C string literals are used because they
- * are the shortest notation. They are used __with a length__ . Null
- * termination doesn't work because there are zero bytes.
+ * other formats.
+ *
+ * C string literals are used because they are the shortest
+ * notation. They are used __with a length__ . Null termination
+ * doesn't work because there are bytes with value zero.
+ *
+ * While the CDE and dCBOR standards are not complete as of mid-2025,
+ * they are unlikely to change, so the tests here are likely correct.
  */
 static const struct FloatTestCase FloatTestCases[] =  {
    /* Zero */
@@ -217,7 +475,7 @@
    {16777217,                                    0.0f,
     {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9},
     {"\xFB\x41\x70\x00\x00\x10\x00\x00\x00", 9}, {"\x1A\x01\x00\x00\x01", 5}},
- 
+
    /* 33554430 -- exponent 24 to test single exponent boundary */
    {33554430,                                    33554430.0f,
     {"\xFA\x4B\xFF\xFF\xFF", 5},                 {"\xFB\x41\x7F\xFF\xFF\xE0\x00\x00\x00", 9},
@@ -248,7 +506,7 @@
     {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
     {"\xFB\x43\x3F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\x00\x1F\xFF\xFF\xFF\xFF\xFF\xFF", 9}},
 
-   /* 18014398509481982 -- exponent 53, 52 bits set in significand (double lacks precision to represent 18014398509481983) */
+   /* 18014398509481982 -- exponent 53, 52 bits set in significand (double lacks precision for 18014398509481983) */
    {18014398509481982,                           0,
     {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9},
     {"\xFB\x43\x4F\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\x1B\x00\x3F\xFF\xFF\xFF\xFF\xFF\xFE", 9}},
@@ -257,7 +515,7 @@
    {18014398509481984,                           18014398509481984.0f,
     {"\xFA\x5A\x80\x00\x00",                 5}, {"\xFB\x43\x50\x00\x00\x00\x00\x00\x00", 9},
     {"\xFA\x5A\x80\x00\x00",                 5}, {"\x1B\x00\x40\x00\x00\x00\x00\x00\x00", 9}},
-   
+
    /* 18446742974197924000.0.0 -- largest single that can convert to uint64 */
    {18446742974197924000.0,                      18446742974197924000.0f,
     {"\xFA\x5F\x7F\xFF\xFF",                 5}, {"\xFB\x43\xEF\xFF\xFF\xE0\x00\x00\x00", 9},
@@ -333,66 +591,6 @@
 };
 
 
-/* Can't use the types double and float here because there's no way in C to
- * construct arbitrary payloads for those types.
- */
-struct NaNTestCase {
-   uint64_t    uDouble; /* Converted to double in test */
-   uint32_t    uSingle; /* Converted to single in test */
-   UsefulBufC  Preferred;
-   UsefulBufC  NotPreferred;
-   UsefulBufC  CDE;
-   UsefulBufC  DCBOR;
-};
-
-/* Always four lines per test case so shell scripts can process into
- * other formats. CDE and DCBOR standards are not complete yet,
- * encodings are a guess. C string literals are used because they
- * are the shortest notation. They are used __with a length__ . Null
- * termination doesn't work because there are zero bytes.
- */
-static const struct NaNTestCase NaNTestCases[] =  {
-
-   /* Payload with most significant bit set, a qNaN by most implementations */
-   {0x7ff8000000000000,                          0x00000000,
-    {"\xF9\x7E\x00", 3},                         {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9},
-    {"\xF9\x7E\x00", 3},                         {"\xF9\x7E\x00", 3}},
-
-   /* Payload with single rightmost set */
-   {0x7ff8000000000001,                          0x00000000,
-    {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x01", 9},
-    {"\xF9\x7E\x00", 3},                         {"\xF9\x7E\x00", 3}},
-
-   /* Payload with 10 leftmost bits set -- converts to half */
-   {0x7ffffc0000000000,                          0x00000000,
-    {"\xF9\x7F\xFF", 3},                         {"\xFB\x7F\xFF\xFC\x00\x00\x00\x00\x00", 9},
-    {"\xF9\x7E\x00", 3},                         {"\xF9\x7E\x00", 3}},
-
-   /* Payload with 10 rightmost bits set -- cannot convert to half */
-   {0x7ff80000000003ff,                          0x00000000,
-    {"\xFB\x7F\xF8\x00\x00\x00\x00\x03\xFF", 9}, {"\xFB\x7F\xF8\x00\x00\x00\x00\x03\xFF", 9},
-    {"\xF9\x7E\x00", 3},                         {"\xF9\x7E\x00", 3}},
-
-   /* Payload with 23 leftmost bits set -- converts to a single */
-   {0x7ffFFFFFE0000000,                          0x7fffffff,
-    {"\xFA\x7F\xFF\xFF\xFF", 5},                 {"\xFB\x7F\xFF\xFF\xFF\xE0\x00\x00\x00", 9},
-    {"\xF9\x7E\x00", 3},                         {"\xF9\x7E\x00", 3}},
-
-   /* Payload with 24 leftmost bits set -- fails to convert to a single */
-   {0x7ffFFFFFF0000000,                          0x00000000,
-    {"\xFB\x7F\xFF\xFF\xFF\xF0\x00\x00\x00", 9}, {"\xFB\x7F\xFF\xFF\xFF\xF0\x00\x00\x00", 9},
-    {"\xF9\x7E\x00", 3},                         {"\xF9\x7E\x00", 3}},
-
-   /* Payload with all bits set */
-   {0x7fffffffffffffff,                          0x00000000,
-    {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
-    {"\xF9\x7E\x00", 3},                         {"\xF9\x7E\x00", 3}},
-
-   /* List terminator */
-   {0, 0, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} }
-};
-
-
 /* Public function. See float_tests.h
  *
  * This is the main test of floating-point encoding / decoding. It is
@@ -405,7 +603,6 @@
 {
    unsigned int                 uTestIndex;
    const struct FloatTestCase  *pTestCase;
-   const struct NaNTestCase    *pNaNTestCase;
    MakeUsefulBufOnStack(        TestOutBuffer, 20);
    UsefulBufC                   TestOutput;
    QCBOREncodeContext           EnCtx;
@@ -413,19 +610,16 @@
    QCBORDecodeContext           DCtx;
    QCBORItem                    Item;
    uint64_t                     uDecoded;
-#ifdef QCBOR_DISABLE_FLOAT_HW_USE
-   uint32_t                     uDecoded2;
-#endif
 
-   /* Test a variety of doubles */
+   /* Test a variety of doubles and some singles */
    for(uTestIndex = 0; FloatTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
       pTestCase = &FloatTestCases[uTestIndex];
 
-      if(uTestIndex == 48) {
+      if(uTestIndex == 16) {
          uDecoded = 1;
       }
 
-      /* Number Encode of Preferred */
+      /* Preferred Encode */
       QCBOREncode_Init(&EnCtx, TestOutBuffer);
       QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
       uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
@@ -433,276 +627,588 @@
       if(uErr != QCBOR_SUCCESS) {
          return MakeTestResultCode(uTestIndex, 1, uErr);;
       }
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       if(UsefulBuf_Compare(TestOutput, pTestCase->Preferred)) {
-         return MakeTestResultCode(uTestIndex, 1, 200);
+         return MakeTestResultCode(uTestIndex, 2, 200);
       }
 
-      /* Number Encode of Not Preferred */
+      if(CompareToCarsten(UsefulBufUtil_CopyDoubleToUint64(pTestCase->dNumber), TestOutput, pTestCase->Preferred)) {
+         return MakeTestResultCode(uTestIndex, 202, 200);
+      }
+#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+      if(UsefulBuf_Compare(TestOutput, pTestCase->NotPreferred)) {
+         return MakeTestResultCode(uTestIndex, 3, 200);
+      }
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+      /* Non-Preferred Encode */
       QCBOREncode_Init(&EnCtx, TestOutBuffer);
       QCBOREncode_AddDoubleNoPreferred(&EnCtx, pTestCase->dNumber);
       uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
 
       if(uErr != QCBOR_SUCCESS) {
-         return MakeTestResultCode(uTestIndex, 2, uErr);;
+         return MakeTestResultCode(uTestIndex, 4, uErr);;
       }
       if(UsefulBuf_Compare(TestOutput, pTestCase->NotPreferred)) {
-         return MakeTestResultCode(uTestIndex, 2, 200);
+         return MakeTestResultCode(uTestIndex, 5, 200);
       }
 
-      /* Number Encode of CDE */
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+      /* Deterministic Encode */
       QCBOREncode_Init(&EnCtx, TestOutBuffer);
       QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_CDE);
       QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
       uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
 
       if(uErr != QCBOR_SUCCESS) {
-         return MakeTestResultCode(uTestIndex, 20, uErr);;
+         return MakeTestResultCode(uTestIndex, 6, uErr);;
       }
       if(UsefulBuf_Compare(TestOutput, pTestCase->CDE)) {
-         return MakeTestResultCode(uTestIndex, 21, 200);
+         return MakeTestResultCode(uTestIndex, 7, 200);
       }
 
-      /* Number Encode of dCBOR */
+      /* dCBOR Encode */
       QCBOREncode_Init(&EnCtx, TestOutBuffer);
       QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR);
       QCBOREncode_AddDouble(&EnCtx, pTestCase->dNumber);
       uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
 
       if(uErr != QCBOR_SUCCESS) {
-         return MakeTestResultCode(uTestIndex, 22, uErr);;
+         return MakeTestResultCode(uTestIndex, 8, uErr);;
       }
       if(UsefulBuf_Compare(TestOutput, pTestCase->DCBOR)) {
-         return MakeTestResultCode(uTestIndex, 23, 200);
+         return MakeTestResultCode(uTestIndex, 9, 200);
       }
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
 
-      if(pTestCase->fNumber != 0) {
-         QCBOREncode_Init(&EnCtx, TestOutBuffer);
-         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR);
-         QCBOREncode_AddFloat(&EnCtx, pTestCase->fNumber);
-         uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
-
-         if(uErr != QCBOR_SUCCESS) {
-            return MakeTestResultCode(uTestIndex, 24, uErr);;
-         }
-         if(UsefulBuf_Compare(TestOutput, pTestCase->DCBOR)) {
-            return MakeTestResultCode(uTestIndex, 25, 200);
-         }
-      }
-
-
-      /* Number Decode of Preferred */
+      /* Decode Preferred */
       QCBORDecode_Init(&DCtx, pTestCase->Preferred, 0);
       uErr = QCBORDecode_GetNext(&DCtx, &Item);
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       if(uErr != QCBOR_SUCCESS) {
-         return MakeTestResultCode(uTestIndex, 3, uErr);;
+         return MakeTestResultCode(uTestIndex, 10, uErr);
       }
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
       if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
-         return MakeTestResultCode(uTestIndex, 4, 0);
+         return MakeTestResultCode(uTestIndex, 11, 0);
       }
       if(isnan(pTestCase->dNumber)) {
          if(!isnan(Item.val.dfnum)) {
-            return MakeTestResultCode(uTestIndex, 5, 0);
+            return MakeTestResultCode(uTestIndex, 12, 0);
          }
       } else {
          if(Item.val.dfnum != pTestCase->dNumber) {
-            return MakeTestResultCode(uTestIndex, 6, 0);
+            return MakeTestResultCode(uTestIndex, 13, 0);
          }
       }
-#else /* QCBOR_DISABLE_FLOAT_HW_USE */
-      /* When QCBOR_DISABLE_FLOAT_HW_USE is set, single-precision is not
-       * converted to double when decoding, so test differently. len == 5
-       * indicates single-precision in the encoded CBOR. */
-      if(pTestCase->Preferred.len == 5) {
+#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+      if(pTestCase->Preferred.len == 3) {
+         if(uErr != QCBOR_ERR_PREFERRED_FLOAT_DISABLED) {
+            return MakeTestResultCode(uTestIndex, 14, uErr);
+         }
+      } else if(pTestCase->Preferred.len == 5) {
+         /* When QCBOR_DISABLE_PREFERRED_FLOAT is set, single-precision is not
+          * converted to double when decoding, so test differently. len == 5
+          * indicates single-precision in the encoded CBOR. */
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex, 15, uErr);
+         }
          if(Item.uDataType != QCBOR_TYPE_FLOAT) {
-            return MakeTestResultCode(uTestIndex, 41, 0);
+            return MakeTestResultCode(uTestIndex, 16, 0);
          }
          if(isnan(pTestCase->dNumber)) {
             if(!isnan(Item.val.fnum)) {
-               return MakeTestResultCode(uTestIndex, 51, 0);
+               return MakeTestResultCode(uTestIndex, 17, 0);
             }
          } else {
             if(Item.val.fnum != pTestCase->fNumber) {
-               return MakeTestResultCode(uTestIndex, 61, 0);
+               return MakeTestResultCode(uTestIndex, 18, 0);
             }
          }
       } else {
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex, 19, uErr);
+         }
          if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
-            return MakeTestResultCode(uTestIndex, 42, 0);
+            return MakeTestResultCode(uTestIndex, 20, 0);
          }
          if(isnan(pTestCase->dNumber)) {
             if(!isnan(Item.val.dfnum)) {
-               return MakeTestResultCode(uTestIndex, 52, 0);
+               return MakeTestResultCode(uTestIndex, 21, 0);
             }
          } else {
             if(Item.val.dfnum != pTestCase->dNumber) {
-               return MakeTestResultCode(uTestIndex, 62, 0);
+               return MakeTestResultCode(uTestIndex, 22, 0);
             }
          }
       }
-#endif /* ! QCBOR_DISABLE_FLOAT_HW_USE */
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
 
-      /* Number Decode of Not Preferred */
+      /* Decode Not Preferred */
       QCBORDecode_Init(&DCtx, pTestCase->NotPreferred, 0);
       uErr = QCBORDecode_GetNext(&DCtx, &Item);
       if(uErr != QCBOR_SUCCESS) {
-         return MakeTestResultCode(uTestIndex, 7, uErr);;
+         return MakeTestResultCode(uTestIndex, 23, uErr);;
       }
       if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
-         return MakeTestResultCode(uTestIndex, 8, 0);
+         return MakeTestResultCode(uTestIndex, 24, 0);
       }
       if(isnan(pTestCase->dNumber)) {
          if(!isnan(Item.val.dfnum)) {
-            return MakeTestResultCode(uTestIndex, 9, 0);
+            return MakeTestResultCode(uTestIndex, 25, 0);
          }
       } else {
          if(Item.val.dfnum != pTestCase->dNumber) {
-            return MakeTestResultCode(uTestIndex, 10, 0);
+            return MakeTestResultCode(uTestIndex, 26, 0);
          }
       }
-
-   }
-
-   /* Test a variety of NaNs with payloads */
-   for(uTestIndex = 0; NaNTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
-      pNaNTestCase = &NaNTestCases[uTestIndex];
-
-
-      if(uTestIndex == 4) {
-         uErr = 99; /* For setting break points for particular tests */
-      }
-
-      /* NaN Encode of Preferred */
-      QCBOREncode_Init(&EnCtx, TestOutBuffer);
-      QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
-      QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
-      uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
-      if(uErr != QCBOR_SUCCESS) {
-         return MakeTestResultCode(uTestIndex+100, 10, uErr);;
-      }
-      if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) {
-         return MakeTestResultCode(uTestIndex+100, 10, 200);
-      }
-
-#ifdef QCBOR_COMPARE_TO_HW_NAN_CONVERSION
-      {
-         /* This test is off by default. It's purpose is to check
-          * QCBOR's mask-n-shift implementation against the HW/CPU
-          * instructions that do conversion between double and single.
-          * It is off because it is only used on occasion to verify
-          * QCBOR and because it is suspected that some HW/CPU does
-          * implement this correctly. NaN payloads are an obscure
-          * feature. */
-         float f;
-         double d, d2;
-
-         d = UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uNumber);
-
-         /* Cast the double to a single and then back to a double and
-          * see if they are equal. If so, then the NaN payload doesn't
-          * have any bits that are lost when converting to single and
-          * it can be safely converted.
-          *
-          * This test can't be done for half-precision because it is
-          * not widely supported.
-          */
-         f = (float)d;
-         d2 = (double)f;
-
-         /* The length of encoded doubles is 9, singles 5 and halves
-          * 3. If there are NaN payload bits that can't be converted,
-          * then the length must be 9.
-          */
-         if((uint64_t)d != (uint64_t)d2 && pNaNTestCase->Preferred.len != 9) {
-            /* QCBOR conversion not the same as HW conversion */
-            return MakeTestResultCode(uTestIndex, 9, 200);
-         }
-      }
-#endif /* QCBOR_COMPARE_TO_HW_NAN_CONVERSION */
-
-
-      /* NaN Encode of Not Preferred */
-      QCBOREncode_Init(&EnCtx, TestOutBuffer);
-      QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
-      QCBOREncode_AddDoubleNoPreferred(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
-      uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
-      if(uErr != QCBOR_SUCCESS) {
-         return MakeTestResultCode(uTestIndex+100, 11, uErr);;
-      }
-      if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
-         return MakeTestResultCode(uTestIndex+100, 11, 200);
-      }
-
-      /* NaN Decode of Not Preferred */
-      QCBORDecode_Init(&DCtx, pNaNTestCase->Preferred, 0);
-      QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
-      uErr = QCBORDecode_GetNext(&DCtx, &Item);
-      if(uErr != QCBOR_SUCCESS) {
-         return MakeTestResultCode(uTestIndex+100, 12, uErr);
-      }
-
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
-
-      uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
-      if(uDecoded != pNaNTestCase->uDouble) {
-         return MakeTestResultCode(uTestIndex+100, 12, 200);
-      }
-#else /* QCBOR_DISABLE_FLOAT_HW_USE */
-      if(pNaNTestCase->Preferred.len == 5) {
-         if(Item.uDataType != QCBOR_TYPE_FLOAT) {
-            return MakeTestResultCode(uTestIndex, 4, 0);
-         }
-
-         uDecoded2 = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum);
-
-         if(uDecoded2 != pNaNTestCase->uSingle) {
-            return MakeTestResultCode(uTestIndex, 4, 0);
-         }
-      } else {
-         if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
-            return MakeTestResultCode(uTestIndex, 4, 0);
-         }
-         uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
-         if(uDecoded != pNaNTestCase->uDouble) {
-            return MakeTestResultCode(uTestIndex+100, 12, 200);
-         }
-      }
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
-
-      /* NaN Decode of Not Preferred */
-      QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0);
-      QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
-      uErr = QCBORDecode_GetNext(&DCtx, &Item);
-      if(uErr != QCBOR_SUCCESS) {
-         return MakeTestResultCode(uTestIndex+100, 13, uErr);
-      }
-      uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
-      if(uDecoded != pNaNTestCase->uDouble) {
-         return MakeTestResultCode(uTestIndex+100, 13, 200);
-      }
-
-
-      /* NaN Encode of DCBOR */
-      QCBOREncode_Init(&EnCtx, TestOutBuffer);
-      QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR | QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
-      QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
-      uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
-      if(uErr != QCBOR_SUCCESS) {
-         return MakeTestResultCode(uTestIndex+100, 14, uErr);;
-      }
-      if(UsefulBuf_Compare(TestOutput, pNaNTestCase->DCBOR)) {
-         return MakeTestResultCode(uTestIndex+100, 14, 200);
-      }
-
    }
 
    return 0;
 }
 
 
+/* Can't use the types double and float here because there's no compile
+ * time initializer in C to construct NaNs.
+
+ * The tests: encode the double in the 4 different ways and see the result is as expected
+ *            encode the single in the 4 different ways and see the result is as expected
+ *            decode the preferred and non-preferred (CDE is always the same as preferred; DCBOR is not reversable)
+ */
+struct NaNTestCase {
+   uint64_t    uDouble; /* Converted to double in test */
+   uint32_t    uSingle; /* Converted to single in test */
+   uint64_t    uExpectedDouble;
+   uint32_t    uExpectedSingle;
+   UsefulBufC  Preferred;
+   UsefulBufC  NotPreferred;
+   UsefulBufC  CDE;
+   UsefulBufC  DCBOR;
+};
+
+/* Always four lines per test case so shell scripts can process into
+ * other formats.
+ *
+ * C string literals are used because they are the shortest
+ * notation. They are used __with a length__ . Null termination
+ * doesn't work because there are bytes with value zero.
+ *
+ * While the CDE and dCBOR standards are not complete as of mid-2025,
+ * they are unlikely to change, so the tests here are likely correct.
+ */
+/* This assumes that the signficand of a float is made up of the qNaN bit and
+ * the payload. The qNaN bit is the most signficant. If not a qNaN, then it
+ * is an sNaN. For an sNaN not to be the floating point value, its significand
+ * must be non-zero. */
+static const struct NaNTestCase NaNTestCases[] =  {
+   /* Reminder: DOUBLE_NAN_BITS | x00 is INFINITY, not a NaN */
+
+   /* double qNaN -- shortens to half */
+   {DOUBLE_NAN_BITS | DOUBLE_QNAN,               0,
+    DOUBLE_NAN_BITS | DOUBLE_QNAN,               0,
+    {"\xF9\x7E\x00", 3},                         {"\xFB\x7F\xF8\x00\x00\x00\x00\x00\x00", 9},
+    {"\xF9\x7E\x00", 3},                         {"\xF9\x7E\x00", 3}},
+
+   /* double negative qNaN -- shortens to half */
+   {DOUBLE_SIGN_MASK | DOUBLE_NAN_BITS | DOUBLE_QNAN, 0,
+    DOUBLE_SIGN_MASK| DOUBLE_NAN_BITS | DOUBLE_QNAN,  0,
+    {"\xF9\xFE\x00", 3},                         {"\xFB\xFF\xF8\x00\x00\x00\x00\x00\x00", 9},
+    {"\xF9\xFE\x00", 3},                         {"\xF9\x7E\x00", 3}},
+
+   /* double sNaN with payload of rightmost bit set -- no shorter encoding */
+   {DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x01,        0,
+    DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x01,        0,
+    {"\xFB\x7F\xF0\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\x7F\xF0\x00\x00\x00\x00\x00\x01", 9},
+    {"\xFB\x7F\xF0\x00\x00\x00\x00\x00\x01", 9}, {"\xF9\x7E\x00", 3}},
+
+   /* double negative sNaN with payload of rightmost bit set -- no shorter encoding */
+   {DOUBLE_SIGN_MASK | DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x01,        0,
+    DOUBLE_SIGN_MASK | DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x01,        0,
+    {"\xFB\xFF\xF0\x00\x00\x00\x00\x00\x01", 9}, {"\xFB\xFF\xF0\x00\x00\x00\x00\x00\x01", 9},
+    {"\xFB\xFF\xF0\x00\x00\x00\x00\x00\x01", 9}, {"\xF9\x7E\x00", 3}},
+
+   /* double qNaN with 9 leftmost payload bits set -- shortens to half */
+   {DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7fc0000000000,  0,
+    DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7fc0000000000,  0,
+    {"\xF9\x7F\xFF", 3},                         {"\xFB\x7F\xFF\xFC\x00\x00\x00\x00\x00", 9},
+    {"\xF9\x7F\xFF", 3},                         {"\xF9\x7E\x00", 3}},
+
+   /* double sNaN with 10 rightmost payload bits set -- no shorter encoding */
+   {DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x03ff,      0,
+    DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x03ff,      0,
+    {"\xFB\x7F\xF0\x00\x00\x00\x00\x03\xFF", 9}, {"\xFB\x7F\xF0\x00\x00\x00\x00\x03\xFF", 9},
+    {"\xFB\x7F\xF0\x00\x00\x00\x00\x03\xFF", 9}, {"\xF9\x7E\x00", 3}},
+
+   /* double qNaN with 22 leftmost payload bits set -- shortens to single */
+   {DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7ffffe0000000,  0,
+    DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7ffffe0000000,  SINGLE_NAN_BITS | 0x7fffff,
+    {"\xFA\x7F\xFF\xFF\xFF", 5},                 {"\xFB\x7F\xFF\xFF\xFF\xE0\x00\x00\x00", 9},
+    {"\xFA\x7F\xFF\xFF\xFF", 5},                 {"\xF9\x7E\x00", 3}},
+
+   /* double negative qNaN with 22 leftmost payload bits set -- shortens to single */
+   {DOUBLE_SIGN_MASK | DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7ffffe0000000,  0,
+    DOUBLE_SIGN_MASK | DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7ffffe0000000,  SINGLE_SIGN_MASK | SINGLE_NAN_BITS | 0x7fffff,
+    {"\xFA\xFF\xFF\xFF\xFF", 5},                 {"\xFB\xFF\xFF\xFF\xFF\xE0\x00\x00\x00", 9},
+    {"\xFA\xFF\xFF\xFF\xFF", 5},                 {"\xF9\x7E\x00", 3}},
+
+   /* double sNaN with 23rd leftmost payload bit set -- shortens to single */
+   {DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x0000020000000,  0,
+    DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x0000020000000,  SINGLE_NAN_BITS | 0x01,
+    {"\xFA\x7F\x80\x00\x01", 5},                 {"\xFB\x7F\xF0\x00\x00\x20\x00\x00\x00", 9},
+    {"\xFA\x7F\x80\x00\x01", 5},                 {"\xF9\x7E\x00", 3}},
+
+   /* double sNaN with randomly chosen bit pattern -- shortens to single */
+   {DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x43d7c40000000,  0,
+    DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x43d7c40000000,  SINGLE_NAN_BITS | 0x21ebe2,
+    {"\xFA\x7F\xA1\xEB\xE2", 5},                 {"\xFB\x7F\xF4\x3D\x7C\x40\x00\x00\x00", 9},
+    {"\xFA\x7F\xA1\xEB\xE2", 5},                 {"\xF9\x7E\x00", 3}},
+
+   /* double sNaN with 23 leftmost payload bits set -- no shorter encoding */
+   {DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x7fffff0000000,  0,
+    DOUBLE_NAN_BITS | DOUBLE_SNAN | 0x7fffff0000000,  0,
+    {"\xFB\x7F\xF7\xFF\xFF\xF0\x00\x00\x00", 9}, {"\xFB\x7F\xF7\xFF\xFF\xF0\x00\x00\x00", 9},
+    {"\xFB\x7F\xF7\xFF\xFF\xF0\x00\x00\x00", 9}, {"\xF9\x7E\x00", 3}},
+
+   /* double qNaN with all bits set -- no shorter encoding */
+   {DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7ffffffffffff,  0,
+    DOUBLE_NAN_BITS | DOUBLE_QNAN | 0x7ffffffffffff,  0,
+    {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9},
+    {"\xFB\x7F\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 9}, {"\xF9\x7E\x00", 3}},
+
+   /* single qNaN with payload 0x00 -- shortens to half */
+   {0,                                           SINGLE_NAN_BITS | SINGLE_QNAN,
+    DOUBLE_NAN_BITS | DOUBLE_QNAN,               0,
+    {"\xF9\x7E\x00", 3},                         {"\xFA\x7F\xC0\x00\x00", 5},
+    {"\xF9\x7E\x00", 3},                         {"\xF9\x7E\x00", 3}},
+
+   /* sNan with payload 0x00 is not a NaN, it's infinity */
+
+   /* single sNan with payload 0x01 -- no shorter encoding */
+   {0,                                           SINGLE_NAN_BITS | SINGLE_SNAN | 0x01,
+    DOUBLE_NAN_BITS | (0x01 << 29),              0,
+    {"\xFA\x7F\x80\x00\x01", 5},                 {"\xFA\x7F\x80\x00\x01", 5},
+    {"\xFA\x7F\x80\x00\x01", 5},                 {"\xF9\x7E\x00", 3}},
+
+   /* single qNaN with 9 bit payload -- shortens to half */
+   {0,                                           SINGLE_NAN_BITS | SINGLE_QNAN | 0x3fe000,
+    DOUBLE_NAN_BITS | ((SINGLE_QNAN | 0x3fe000ULL) << 29),   0,
+    {"\xF9\x7F\xFF", 3},                         {"\xFA\x7F\xFF\xE0\x00", 5},
+    {"\xF9\x7F\xFF", 3},                         {"\xF9\x7E\x00", 3}},
+
+   /* single qNaN with 10 bit payload -- no shorter encoding */
+   {0,                                           SINGLE_NAN_BITS | SINGLE_QNAN | 0x3ff000,
+    DOUBLE_NAN_BITS | ((SINGLE_QNAN | 0x3ff000ULL) << 29), 0,
+    {"\xFA\x7F\xFF\xF0\x00", 5},                 {"\xFA\x7F\xFF\xF0\x00", 5},
+    {"\xFA\x7F\xFF\xF0\x00", 5},                 {"\xF9\x7E\x00", 3}},
+
+   /* single sNaN with 9 bit payload -- shortens to half */
+   {0,                                           SINGLE_NAN_BITS | SINGLE_SNAN | 0x3fe000,
+    DOUBLE_NAN_BITS | ((SINGLE_SNAN | 0x3fe000ULL) << 29), 0,
+    {"\xF9\x7D\xFF", 3},                         {"\xFA\x7F\xBF\xE0\x00", 5},
+    {"\xF9\x7D\xFF", 3},                         {"\xF9\x7E\x00", 3}},
+
+   /* single sNaN with 10 bit payload -- no shorter encoding */
+   {0,                                           SINGLE_NAN_BITS | SINGLE_SNAN | 0x3ff000,
+    DOUBLE_NAN_BITS | ((SINGLE_SNAN | 0x3ff000ULL) << 29), 0,
+    {"\xFA\x7F\xBF\xF0\x00", 5},                 {"\xFA\x7F\xBF\xF0\x00", 5},
+    {"\xFA\x7F\xBF\xF0\x00", 5},                 {"\xF9\x7E\x00", 3}},
+
+   /* List terminator */
+   {0, 0, 0, 0, {NULL, 0}, {NULL, 0}, {NULL, 0}, {NULL, 0} }
+};
+
 
 /* Public function. See float_tests.h */
-int32_t 
+int32_t
+NaNPayloadsTest(void)
+{
+   const struct NaNTestCase    *pNaNTestCase;
+   unsigned int                 uTestIndex;
+   QCBORError                   uErr;
+   QCBOREncodeContext           EnCtx;
+   MakeUsefulBufOnStack(        TestOutBuffer, 20);
+   UsefulBufC                   TestOutput;
+   QCBORDecodeContext           DCtx;
+   QCBORItem                    Item;
+   uint64_t                     uDecoded;
+
+   /* Test a variety of NaNs with payloads */
+   for(uTestIndex = 0; NaNTestCases[uTestIndex].Preferred.len != 0; uTestIndex++) {
+      pNaNTestCase = &NaNTestCases[uTestIndex];
+
+      if(uTestIndex == 7) {
+         uErr = 99; /* For setting break points for a particular test */
+      }
+
+      if(pNaNTestCase->uDouble) {
+         /* NaN Encode of Preferred */
+         QCBOREncode_Init(&EnCtx, TestOutBuffer);
+         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
+         QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
+         uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex+100, 10, uErr);;
+         }
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+         if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) {
+            return MakeTestResultCode(uTestIndex+100, 11, 200);
+         }
+         if(CompareToCarsten(pNaNTestCase->uDouble, TestOutput, pNaNTestCase->Preferred)) {
+            return MakeTestResultCode(uTestIndex+100, 12, 200);
+         }
+#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+         if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
+            return MakeTestResultCode(uTestIndex+100, 122, 200);
+         }
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
+
+         if(HWCheckFloatToDouble(pNaNTestCase->uDouble, pNaNTestCase->uSingle)) {
+            return MakeTestResultCode(uTestIndex+100, 121, 200);
+         }
+
+         /* NaN Encode of Not Preferred */
+         QCBOREncode_Init(&EnCtx, TestOutBuffer);
+         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
+         QCBOREncode_AddDoubleNoPreferred(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
+         uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex+100, 13, uErr);;
+         }
+         if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
+            return MakeTestResultCode(uTestIndex+100, 14, 200);
+         }
+
+         /* NaN Decode of Preferred */
+         QCBORDecode_Init(&DCtx, pNaNTestCase->Preferred, 0);
+         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
+         uErr = QCBORDecode_GetNext(&DCtx, &Item);
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex+100, 15, uErr);
+         }
+         uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
+         if(uDecoded != pNaNTestCase->uDouble) {
+            return MakeTestResultCode(uTestIndex+100, 11, 200);
+         }
+#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+         if(pNaNTestCase->Preferred.len == 9) {
+            if(uErr != QCBOR_SUCCESS) {
+               return MakeTestResultCode(uTestIndex+100, 17, uErr);
+            }
+
+            uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
+            if(uDecoded != pNaNTestCase->uDouble) {
+               return MakeTestResultCode(uTestIndex+100, 18, 200);
+            }
+         } else if(pNaNTestCase->Preferred.len == 5) {
+            if(Item.uDataType != QCBOR_TYPE_FLOAT) {
+               return MakeTestResultCode(uTestIndex, 19, 0);
+            }
+
+            uint32_t uDecoded2x = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum);
+
+            if(uDecoded2x != pNaNTestCase->uExpectedSingle) {
+               return MakeTestResultCode(uTestIndex, 20, 0);
+            }
+         } else {
+            /* Serialized to half precision */
+            if(Item.uDataType != QCBOR_TYPE_NONE) {
+               return MakeTestResultCode(uTestIndex, 21, 0);
+            }
+         }
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+         /* NaN Decode of Not Preferred */
+         QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0);
+         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
+         uErr = QCBORDecode_GetNext(&DCtx, &Item);
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex+100, 22, uErr);
+         }
+         uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
+         if(uDecoded != pNaNTestCase->uDouble) {
+            return MakeTestResultCode(uTestIndex+100, 23, 200);
+         }
+
+         /* NaN Encode of CDE */
+         QCBOREncode_Init(&EnCtx, TestOutBuffer);
+         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_CDE| QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
+         QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
+         uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex+100, 24, uErr);;
+         }
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+         if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) {
+            return MakeTestResultCode(uTestIndex+100, 241, 200);
+         }
+#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+         if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
+            return MakeTestResultCode(uTestIndex+100, 25, 200);
+         }
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+         /* NaN Encode of DCBOR */
+         QCBOREncode_Init(&EnCtx, TestOutBuffer);
+         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR | QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
+         QCBOREncode_AddDouble(&EnCtx, UsefulBufUtil_CopyUint64ToDouble(pNaNTestCase->uDouble));
+         uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex+100, 26, uErr);;
+         }
+         if(UsefulBuf_Compare(TestOutput, pNaNTestCase->DCBOR)) {
+            return MakeTestResultCode(uTestIndex+100, 27, 200);
+         }
+#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+         if(uErr != QCBOR_ERR_PREFERRED_FLOAT_DISABLED) {
+            return MakeTestResultCode(uTestIndex+100, 28, uErr);
+         }
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+      } else {
+         /* --- uSingle tests ---- */
+         /* NaN Encode of Preferred */
+         QCBOREncode_Init(&EnCtx, TestOutBuffer);
+         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
+         QCBOREncode_AddFloat(&EnCtx, UsefulBufUtil_CopyUint32ToFloat(pNaNTestCase->uSingle));
+         uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex+100, 29, uErr);;
+         }
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+         if(UsefulBuf_Compare(TestOutput, pNaNTestCase->Preferred)) {
+            return MakeTestResultCode(uTestIndex+100, 30, 200);
+         }
+#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+         if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
+            return MakeTestResultCode(uTestIndex+100, 31, 200);
+         }
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+         /* NaN Encode of Not Preferred */
+         QCBOREncode_Init(&EnCtx, TestOutBuffer);
+         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
+         QCBOREncode_AddFloatNoPreferred(&EnCtx, UsefulBufUtil_CopyUint32ToFloat(pNaNTestCase->uSingle));
+         uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex+100, 32, uErr);;
+         }
+         if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
+            return MakeTestResultCode(uTestIndex+100, 33, 200);
+         }
+
+         /* NaN Decode of Preferred */
+         QCBORDecode_Init(&DCtx, pNaNTestCase->Preferred, 0);
+         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
+         uErr = QCBORDecode_GetNext(&DCtx, &Item);
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex+100, 34, uErr);
+         }
+         uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
+         if(uDecoded != pNaNTestCase->uExpectedDouble) {
+            return MakeTestResultCode(uTestIndex+100, 35, 200);
+         }
+#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+         if(pNaNTestCase->Preferred.len == 5) {
+            uint32_t uDecoded2x = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum);
+            if(uDecoded2x != pNaNTestCase->uSingle) {
+               return MakeTestResultCode(uTestIndex+100, 36, 200);
+            }
+         } else {
+            if(uErr != QCBOR_ERR_PREFERRED_FLOAT_DISABLED) {
+               return MakeTestResultCode(uTestIndex+100, 37, 200);
+            }
+         }
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+         /* NaN Decode of Not Preferred */
+         QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0);
+         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
+         uErr = QCBORDecode_GetNext(&DCtx, &Item);
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex+100, 38, uErr);
+         }
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+         uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
+         if(uDecoded != pNaNTestCase->uExpectedDouble) {
+            return MakeTestResultCode(uTestIndex+100, 39, 200);
+         }
+#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+         if(pNaNTestCase->NotPreferred.len == 5) {
+            uint32_t uDecoded22 = UsefulBufUtil_CopyFloatToUint32(Item.val.fnum);
+            if(uDecoded22 != pNaNTestCase->uSingle) {
+               return MakeTestResultCode(uTestIndex+100, 40, 200);
+            }
+         }
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+         if(HWCheckDoubleToFloat(pNaNTestCase->uSingle, pNaNTestCase->uExpectedDouble)) {
+            return MakeTestResultCode(uTestIndex+100, 401, 200);
+         }
+
+         /* NaN Encode of CDE */
+         QCBOREncode_Init(&EnCtx, TestOutBuffer);
+         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_CDE| QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
+         QCBOREncode_AddFloat(&EnCtx, UsefulBufUtil_CopyUint32ToFloat(pNaNTestCase->uSingle));
+         uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex+100, 41, uErr);;
+         }
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+         if(UsefulBuf_Compare(TestOutput, pNaNTestCase->CDE)) {
+            return MakeTestResultCode(uTestIndex+100, 42, 200);
+         }
+#else /* ! #ifndef QCBOR_DISABLE_PREFERRED_FLOAT */
+         if(UsefulBuf_Compare(TestOutput, pNaNTestCase->NotPreferred)) {
+            return MakeTestResultCode(uTestIndex+100, 43, 200);
+         }
+#endif /* ! #ifndef QCBOR_DISABLE_PREFERRED_FLOAT */
+
+         /* NaN Encode of DCBOR */
+         QCBOREncode_Init(&EnCtx, TestOutBuffer);
+         QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR | QCBOR_ENCODE_CONFIG_ALLOW_NAN_PAYLOAD);
+         QCBOREncode_AddFloat(&EnCtx, UsefulBufUtil_CopyUint32ToFloat(pNaNTestCase->uSingle));
+         uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+         if(uErr != QCBOR_SUCCESS) {
+            return MakeTestResultCode(uTestIndex+100, 44, uErr);;
+         }
+         if(UsefulBuf_Compare(TestOutput, pNaNTestCase->DCBOR)) {
+            return MakeTestResultCode(uTestIndex+100, 45, 200);
+         }
+#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+         if(uErr != QCBOR_ERR_PREFERRED_FLOAT_DISABLED) {
+            return MakeTestResultCode(uTestIndex+100, 46, uErr);
+         }
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+      }
+   }
+
+   /* Special one-off for 100% coverage */
+   QCBOREncode_Init(&EnCtx, TestOutBuffer);
+   QCBOREncode_Config(&EnCtx, QCBOR_ENCODE_CONFIG_DCBOR);
+   QCBOREncode_AddFloat(&EnCtx, 0);
+   uErr = QCBOREncode_Finish(&EnCtx, &TestOutput);
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+   if(uErr != QCBOR_SUCCESS) {
+      return MakeTestResultCode(199, 100, uErr);;
+   }
+   if(UsefulBuf_Compare(TestOutput, UsefulBuf_FROM_SZ_LITERAL("\x00"))) {
+      return MakeTestResultCode(199, 101, 200);
+   }
+#else /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+   if(uErr != QCBOR_ERR_PREFERRED_FLOAT_DISABLED) {
+      return MakeTestResultCode(uTestIndex+100, 261, uErr);
+   }
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
+
+   return 0;
+}
+
+
+/* Public function. See float_tests.h */
+int32_t
 HalfPrecisionAgainstRFCCodeTest(void)
 {
    QCBORItem          Item;
@@ -753,7 +1259,7 @@
    return 0;
 }
 
-#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
+#endif /* ! USEFULBUF_DISABLE_ALL_FLOAT */
 
 
 /*
@@ -766,10 +1272,10 @@
  *  NaN,  // Double
  *  Infinity, // Double
  *  0.0,  // Half (Duplicate because of use in encode tests)
- *  3.140000104904175, // Single
- *  0.0,  // Single
- *  NaN,  // Single
- *  Infinity, // Single
+ *  3.140000104904175, // Single  XXX
+ *  0.0,  // Single  XXX
+ *  NaN,  // Single XXX
+ *  Infinity, // Single XXX
  *  {100: 0.0, 101: 3.1415926, "euler": 2.718281828459045, 105: 0.0,
  *   102: 0.0, 103: 3.141592502593994, "euler2": 2.7182817459106445, 106: 0.0}]
  */
@@ -840,7 +1346,7 @@
 GeneralFloatEncodeTests(void)
 {
    /* See FloatNumberTests() for tests that really cover lots of float values.
-    * Add new tests for new values or decode modes there. 
+    * Add new tests for new values or decode modes there.
     * This test is primarily to cover all the float encode methods. */
 
    UsefulBufC Encoded;
@@ -904,15 +1410,15 @@
 
 
 /* Public function. See float_tests.h */
-int32_t 
+int32_t
 GeneralFloatDecodeTests(void)
 {
-   /* See FloatNumberTests() for tests that really cover lots of float values */
+   /* See FloatNumberTests() for tests that really covers the float values.
+    * This is retained to cover GetDouble() and decode of a single 0 */
 
    QCBORItem          Item;
    QCBORError         uErr;
    QCBORDecodeContext DC;
-
    UsefulBufC TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
    QCBORDecode_Init(&DC, TestData, 0);
 
@@ -923,7 +1429,7 @@
 
    /* 0.0 half-precision */
    uErr = QCBORDecode_GetNext(&DC, &Item);
-   if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
+   if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS)
 #ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || Item.uDataType != QCBOR_TYPE_DOUBLE
       || Item.val.dfnum != 0.0
@@ -988,7 +1494,7 @@
 
    /* 0.0 half-precision (again) */
    uErr = QCBORDecode_GetNext(&DC, &Item);
-   if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
+   if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS)
 #ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || Item.uDataType != QCBOR_TYPE_DOUBLE
       || Item.val.dfnum != 0.0
@@ -1003,13 +1509,13 @@
    uErr = QCBORDecode_GetNext(&DC, &Item);
    if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || Item.uDataType != QCBOR_TYPE_DOUBLE
       || 3.1400001049041748 != Item.val.dfnum
 #else /* QCBOR_DISABLE_FLOAT_HW_USE */
       || Item.uDataType != QCBOR_TYPE_FLOAT
       || 3.140000f != Item.val.fnum
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
 #else /* USEFULBUF_DISABLE_ALL_FLOAT */
       || Item.uDataType != QCBOR_TYPE_NONE
 #endif /* USEFULBUF_DISABLE_ALL_FLOAT */
@@ -1021,13 +1527,13 @@
    uErr = QCBORDecode_GetNext(&DC, &Item);
    if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || Item.uDataType != QCBOR_TYPE_DOUBLE
       || Item.val.dfnum != 0.0
 #else /* QCBOR_DISABLE_FLOAT_HW_USE */
       || Item.uDataType != QCBOR_TYPE_FLOAT
       || Item.val.fnum != 0.0f
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
 #else /* USEFULBUF_DISABLE_ALL_FLOAT */
       || Item.uDataType != QCBOR_TYPE_NONE
 #endif /* USEFULBUF_DISABLE_ALL_FLOAT */
@@ -1039,13 +1545,13 @@
    uErr = QCBORDecode_GetNext(&DC, &Item);
    if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || Item.uDataType != QCBOR_TYPE_DOUBLE
       || !isnan(Item.val.dfnum)
-#else /* QCBOR_DISABLE_FLOAT_HW_USE */
+#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
       || Item.uDataType != QCBOR_TYPE_FLOAT
       || !isnan(Item.val.fnum)
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
 #else /* USEFULBUF_DISABLE_ALL_FLOAT */
       || Item.uDataType != QCBOR_TYPE_NONE
 #endif /* USEFULBUF_DISABLE_ALL_FLOAT */
@@ -1057,13 +1563,13 @@
    uErr = QCBORDecode_GetNext(&DC, &Item);
    if(uErr != FLOAT_ERR_CODE_NO_FLOAT(QCBOR_SUCCESS)
 #ifndef USEFULBUF_DISABLE_ALL_FLOAT
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || Item.uDataType != QCBOR_TYPE_DOUBLE
       || Item.val.dfnum != INFINITY
-#else /* QCBOR_DISABLE_FLOAT_HW_USE */
+#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
       || Item.uDataType != QCBOR_TYPE_FLOAT
       || Item.val.fnum != INFINITY
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
 #else /* USEFULBUF_DISABLE_ALL_FLOAT */
       || Item.uDataType != QCBOR_TYPE_NONE
 #endif /* USEFULBUF_DISABLE_ALL_FLOAT */
@@ -1083,7 +1589,7 @@
    /* 0.0 half-precision */
    QCBORDecode_GetDouble(&DC, &d);
    uErr = QCBORDecode_GetAndResetError(&DC);
-   if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
+   if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS)
 #ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || d != 0.0
 #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
@@ -1122,7 +1628,7 @@
    /* 0.0 half-precision */
    QCBORDecode_GetDouble(&DC, &d);
    uErr = QCBORDecode_GetAndResetError(&DC);
-   if(uErr != FLOAT_ERR_CODE_NO_HALF_PREC(QCBOR_SUCCESS)
+   if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS)
 #ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || d != 0.0
 #endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
@@ -1133,10 +1639,10 @@
    /* 3.140000104904175 single-precision */
    QCBORDecode_GetDouble(&DC, &d);
    uErr = QCBORDecode_GetAndResetError(&DC);
-   if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+   if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS) /* Different in 2.0 and 1.6 */
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || d != 3.140000104904175
-#endif
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
       ) {
       return MakeTestResultCode(1, 7, uErr);
    }
@@ -1144,20 +1650,20 @@
    /* 0.0 single-precision */
    QCBORDecode_GetDouble(&DC, &d);
    uErr = QCBORDecode_GetAndResetError(&DC);
-   if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+   if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS) /* Different in 2.0 and 1.6 */
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || d != 0.0
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
       ) {
       return MakeTestResultCode(1, 8, uErr);
    }
 
    /* NaN single-precision */
    QCBORDecode_GetDouble(&DC, &d);
-   if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+   if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS) /* Different in 2.0 and 1.6 */
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || !isnan(d)
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
       ) {
       return MakeTestResultCode(1, 9, uErr);
    }
@@ -1165,60 +1671,15 @@
    /* Infinity single-precision */
    QCBORDecode_GetDouble(&DC, &d);
    uErr = QCBORDecode_GetAndResetError(&DC);
-   if(uErr != FLOAT_ERR_CODE_NO_FLOAT_HW(QCBOR_SUCCESS)
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+   if(uErr != FLOAT_ERR_CODE_NO_PREF_FLOAT(QCBOR_SUCCESS) /* Different in 2.0 and 1.6 */
+#ifndef QCBOR_DISABLQCBOR_DISABLE_PREFERRED_FLOATE_FLOAT_HW_USE
       || d != INFINITY
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
       ) {
       return MakeTestResultCode(1, 10, uErr);
    }
 
 #endif /* USEFULBUF_DISABLE_ALL_FLOAT */
-
    return 0;
 }
 
-
-
-#ifdef NAN_EXPERIMENT
-/*
- Code for checking what the double to float cast does with
- NaNs.  Not run as part of tests. Keep it around to
- be able to check various platforms and CPUs.
- */
-
-#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
-#define DOUBLE_NUM_EXPONENT_BITS    (11)
-#define DOUBLE_NUM_SIGN_BITS        (1)
-
-#define DOUBLE_SIGNIFICAND_SHIFT    (0)
-#define DOUBLE_EXPONENT_SHIFT       (DOUBLE_NUM_SIGNIFICAND_BITS)
-#define DOUBLE_SIGN_SHIFT           (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
-
-#define DOUBLE_SIGNIFICAND_MASK     (0xfffffffffffffULL) // The lower 52 bits
-#define DOUBLE_EXPONENT_MASK        (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
-#define DOUBLE_SIGN_MASK            (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
-#define DOUBLE_QUIET_NAN_BIT        (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
-
-
-static int NaNExperiments() {
-    double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
-    double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
-    double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
-
-    float f1 = (float)dqNaN;
-    float f2 = (float)dsNaN;
-    float f3 = (float)dqNaNPayload;
-
-
-    uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
-    uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
-    uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
-
-    // Result of this on x86 is that every NaN is a qNaN. The intel
-    // CVTSD2SS instruction ignores the NaN payload and even converts
-    // a sNaN to a qNaN.
-
-    return 0;
-}
-#endif /* NAN_EXPERIMENT */