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.


* Single to Double conversion now uses SW, not CPU

* Fix #ifdef fan out and documentation

* Fix some error numbers; code tidy

* Fix error code

---------

Co-authored-by: Laurence Lundblade <lgl@securitytheory.com>
diff --git a/test/float_tests.c b/test/float_tests.c
index b74d939..a2c7238 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
@@ -320,7 +320,7 @@
    QCBORDecodeContext           DCtx;
    QCBORItem                    Item;
    uint64_t                     uDecoded;
-#ifdef QCBOR_DISABLE_FLOAT_HW_USE
+#ifdef QCBOR_DISABLE_PREFERRED_FLOAT
    uint32_t                     uDecoded2;
 #endif
 
@@ -329,7 +329,7 @@
       pTestCase = &DoubleTestCases[uTestIndex];
 
      // if(pTestCase->dNumber == 1.1754943508222874E-38) {
-         if(uTestIndex == 19) {
+         if(uTestIndex == 16) {
          uErr = 99; /* For setting break points for particular tests */
       }
 
@@ -363,7 +363,7 @@
       if(uErr != QCBOR_SUCCESS) {
          return MakeTestResultCode(uTestIndex, 3, uErr);;
       }
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       if(Item.uDataType != QCBOR_TYPE_DOUBLE) {
          return MakeTestResultCode(uTestIndex, 4, 0);
       }
@@ -376,7 +376,7 @@
             return MakeTestResultCode(uTestIndex, 6, 0);
          }
       }
-#else /* QCBOR_DISABLE_FLOAT_HW_USE */
+#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
       /* 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. */
@@ -407,7 +407,7 @@
             }
          }
       }
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
 
       /* Number Decode of Not Preferred */
       QCBORDecode_Init(&DCtx, pTestCase->NotPreferred, 0);
@@ -505,13 +505,13 @@
          return MakeTestResultCode(uTestIndex+100, 12, uErr);
       }
 
-#ifndef QCBOR_DISABLE_FLOAT_HW_USE
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
 
       uDecoded = UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum);
       if(uDecoded != pNaNTestCase->uDouble) {
          return MakeTestResultCode(uTestIndex+100, 12, 200);
       }
-#else /* QCBOR_DISABLE_FLOAT_HW_USE */
+#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
       if(pNaNTestCase->Preferred.len == 5) {
          if(Item.uDataType != QCBOR_TYPE_FLOAT) {
             return MakeTestResultCode(uTestIndex, 4, 0);
@@ -531,7 +531,7 @@
             return MakeTestResultCode(uTestIndex+100, 12, 200);
          }
       }
-#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
 
       /* NaN Decode of Not Preferred */
       QCBORDecode_Init(&DCtx, pNaNTestCase->NotPreferred, 0);
@@ -852,13 +852,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 */
+#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
       || 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 */
@@ -870,13 +870,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 */
+#else /* QCBOR_DISABLE_PREFERRED_FLOAT */
       || 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 */
@@ -888,13 +888,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 */
@@ -906,13 +906,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 */
@@ -982,10 +982,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_HALF_PREC(QCBOR_SUCCESS)
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || d != 3.140000104904175
-#endif
+#endif /* ! QCBOR_DISABLE_PREFERRED_FLOAT */
       ) {
       return MakeTestResultCode(1, 7, uErr);
    }
@@ -993,8 +993,8 @@
    /* 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_HALF_PREC(QCBOR_SUCCESS)
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || d != 0.0
 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
       ) {
@@ -1003,8 +1003,8 @@
 
    /* 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_HALF_PREC(QCBOR_SUCCESS)
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || !isnan(d)
 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
       ) {
@@ -1014,8 +1014,8 @@
    /* 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_HALF_PREC(QCBOR_SUCCESS)
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
       || d != INFINITY
 #endif /* QCBOR_DISABLE_FLOAT_HW_USE */
       ) {