Merge floating-point disabling into spiffy decode
diff --git a/README.md b/README.md
index c86ef1f..230d6a3 100644
--- a/README.md
+++ b/README.md
@@ -100,15 +100,7 @@
 project. Hopefully the easy portability of this implementation makes
 this work straight away, whatever your development environment is.
 
-The files ieee754.c and ieee754.h are support for half-precision
-floating-point. The encoding side of the floating-point functionality
-is about 500 bytes. If it is never called because no floating-point
-numbers are ever encoded, all 500 bytes will be dead stripped and not
-impact code size. The decoding side is about 150 bytes of object
-code. It is never dead stripped because it directly referenced by the
-core decoder, however it doesn't add very much to the size.
-
-The test directory includes some tests that are nearly as portable as
+The test directory includes the tests that are nearly as portable as
 the main implementation.  If your development environment doesn't
 support UNIX style command line and make, you should be able to make a
 simple project and add the test files to it.  Then just call
@@ -117,10 +109,10 @@
 While this code will run fine without configuration, there are several
 C pre processor macros that can be #defined in order to:
 
-* use a more efficient implementation
-  * to reduce code size
-  * to improve performance (a little)
-* remove features to reduce code size
+ * use a more efficient implementation 
+ * to reduce code size
+ * to improve performance (a little)
+ * remove features to reduce code size
 
 See the comment sections on "Configuration" in inc/UsefulBuf.h.
 
@@ -156,6 +148,32 @@
 For example map searching and duplicate detection is reused.
 This may reduce object code size.
 
+## Floating Point Support
+
+By default, all floating-point features are supported. This includes
+encoding and decoding of half-precision, CBOR preferred serialization
+for floating-point and floating-point epoch dates.
+
+If full floating-point is not needed the following #defines can be
+used to reduce object code size.
+
+QCBOR_DISABLE_FLOAT_HW_USE -- Avoid all use of floating-point hardware.
+
+QCBOR_DISABLE_PREFERRED_FLOAT -- Eliminates support for half-precision
+and CBOR preferred serialization.
+
+Even if these are #defined, QCBOR can still encode and decode basic
+floating point.
+
+Defining QCBOR_DISABLE_PREFERRED_FLOAT will reduce object code size by
+about 900 bytes, though 550 of these bytes can be avoided without the
+define by just not calling any of the functions that encode
+floating-point numbers.
+
+Defining QCBOR_DISABLE_FLOAT_HW_USE will save a small amount of object
+code. Its main use is on CPUs that have no floating-point hardware.
+
+See discussion in qcbor_encode.h for details.
 
 ## Code Size
 
@@ -163,25 +181,31 @@
 
     |               | smallest | largest |  
     |---------------|----------|---------|
-    | encode only   |     1000 |    1800 |
-    | decode only   |     2600 |    4250 |
-    | combined      |     3600 |    6050 |
+    | encode only   |     1000 |    2100 |
+    | decode only   |     2500 |    4300 |
+    | combined      |     3500 |    6400 |
     
 The following are some ways to make the code smaller.
 
-The gcc compiler output is usually smaller than llvm because stack guards are off by default.
-You can all turn of stack gaurds with llvm. It is safe to turn off stack guards with
-this code because Usefulbuf provides similar defenses and this code was carefully
-written to be defensive.
+The gcc compiler output is usually smaller than llvm because stack
+guards are off by default (be sure you actually have gcc and not llvm
+installed to be invoked by the gcc command). You can also turn off
+stack gaurds with llvm. It is safe to turn off stack guards with this
+code because Usefulbuf provides similar defenses and this code was
+carefully written to be defensive.
 
-Use fewer of the encode functions, particularly avoid floating point and bstr wrapping. This 
-combined with dead-stripping works very well to automatically omit functions
-that are not needed on the encode side.
+Use fewer of the encode functions, particularly avoid floating-point
+and bstr wrapping. This combined with dead-stripping works very well
+to automatically omit functions that are not needed on the encode
+side.
 
-Disable features with defines like QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA. 
-This is the primary means of reducing code on the decode side.  More of these defines are 
-planned than are currently implemented, but they are a little complex to implement because
-all the configurations must be tested. 
+Disable features with defines like
+QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA (saves about 400 bytes) and
+QCBOR_DISABLE_PREFERRED_FLOAT (saves about 900 bytes).  This is the
+primary means of reducing code on the decode side.  More of these
+defines are planned than are currently implemented, but they are a
+little complex to implement because all the combination configurations 
+must be tested.
 
 ## Other Software Using QCBOR
 
@@ -222,6 +246,10 @@
 * Mark Bapst for sponsorship and release as open source by Qualcomm
 * Sachin Sharma for release through CAF
 * Tamas Ban for porting to TF-M and 32-bit ARM
+* Michael Eckel for Makefile improvements
+* Jan Jongboom for indefinite length encoding
+* Peter Uiterwijk for error strings and other
+
 
 ## Copyright and License
 
diff --git a/inc/qcbor/qcbor_common.h b/inc/qcbor/qcbor_common.h
index bc2cd4b..fa927c7 100644
--- a/inc/qcbor/qcbor_common.h
+++ b/inc/qcbor/qcbor_common.h
@@ -368,7 +368,14 @@
 
    /** Trying to get something by label when not entered into a
        map.  */
-   QCBOR_ERR_NOT_A_MAP = 33
+   QCBOR_ERR_NOT_A_MAP = 33,
+
+   /** Decoding of floating-point epoch dates is unsupported and a
+        floating-point date was encountered by the decoder. */
+   QCBOR_ERR_FLOAT_DATE_UNSUPPORTED = 34,
+
+   /** Support for half-precision float decoding is disabled. */
+   QCBOR_ERR_HALF_PRECISION_UNSUPPORTED = 35
 
    /* This is stored in uint8_t; never add values > 255 */
 } QCBORError;
diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h
index eca4742..bb53c24 100644
--- a/inc/qcbor/qcbor_decode.h
+++ b/inc/qcbor/qcbor_decode.h
@@ -336,6 +336,8 @@
       uint16_t    uCount;
       /** The value for @c uDataType @ref QCBOR_TYPE_DOUBLE. */
       double      dfnum;
+      /** The value for @c uDataType @ref QCBOR_TYPE_FLOAT. */
+      float       fnum;
       /** The value for @c uDataType @ref QCBOR_TYPE_DATE_EPOCH. */
       struct {
          int64_t  nSeconds;
@@ -994,16 +996,17 @@
 
  @param[in]  pCtx  The context to check.
 
- @retval  QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN   The CBOR is not well-formed
- as some map or array was not closed off. This should always be treated as an
- unrecoverable error.
+ @retval QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN The CBOR is not well-formed
+          as some map or array was not closed off. This should always
+          be treated as an unrecoverable error.
 
- @retval QCBOR_ERR_EXTRA_BYTES The CBOR was decoded correctly and
- all maps and arrays are closed, but some of the bytes in the input were not consumed.
- This may or may not be considered an error.
+ @retval QCBOR_ERR_EXTRA_BYTES The CBOR was decoded correctly and all
+         maps and arrays are closed, but some of the bytes in the
+         input were not consumed.  This may or may not be considered
+         an error.
 
  @retval QCBOR_SUCCES There were no errors and all bytes were
- consumed.
+         consumed.
 
  This should always be called to determine if all maps and arrays
  where correctly closed and that the CBOR was well-formed.
diff --git a/inc/qcbor/qcbor_encode.h b/inc/qcbor/qcbor_encode.h
index ba18167..c3cc53a 100644
--- a/inc/qcbor/qcbor_encode.h
+++ b/inc/qcbor/qcbor_encode.h
@@ -210,7 +210,7 @@
 
  Note that when you nest arrays or maps in a map, the nested array or
  map has a label.
- 
+
  Many CBOR-based protocols start with an array or map. This makes them
  self-delimiting. No external length or end marker is needed to know
  the end. It is also possible not start this way, in which case this
@@ -251,6 +251,63 @@
  structure of tagged data not built-in (if there is any) has to be
  implemented by the caller.
 
+ @anchor Floating-Point
+ By default QCBOR fully supports IEEE 754 floating-point:
+  - Encode/decode of double, single and half-precision
+  - CBOR preferred serialization of floating-point
+  - Floating-point epoch dates
+
+ For the most part, the type double is used in the interface for
+ floating-point values. In the default configuration, all decoded
+ floating-point values are returned as a double.
+
+ With CBOR preferred serialization, the encoder outputs the smallest
+ representation of the double or float that preserves precision. Zero,
+ NaN and infinity are always output as a half-precision, each taking
+ just 2 bytes. This reduces the number of bytes needed to encode
+ doubles and floats, especially if the zero, NaN and infinity are
+ frequently used.
+
+ To avoid use of preferred serialization when encoding, use
+ QCBOREncode_AddDoubleNoPreferred() or
+ QCBOREncode_AddFloatNoPreferred().
+
+ This implementation of preferred floating-point serialization and
+ half-precision does not depend on the CPU having floating-point HW or
+ the compiler bringing in a (sometimes large) library to compensate
+ for lack of CPU support. The implementation uses shifts and masks
+ rather than floating-point functions. It does however add object
+ code.
+
+ To reduce object code, define QCBOR_DISABLE_PREFERRED_FLOAT. This
+ will eliminate all support for preferred serialization and
+ half-precision. An error will be returned when attempting to decode
+ half-precision. A float will always be encoded and decoded as 32-bits
+ and a double will always be encoded and decoded as 64 bits. This
+ will reduce object code by about 900 bytes.
+
+ Note that even if QCBOR_DISABLE_PREFERRED_FLOAT is not defined all
+ the float-point encoding object code can be avoided by never calling
+ any functions that encode double or float. Just not calling
+ floating-point functions will reduce object code by about 500 bytes.
+
+ On CPUs that have no floating-point hardware,
+ QCBOR_DISABLE_FLOAT_HW_USE should be defined in most cases. If it is
+ not, then the compiler will bring in possibly large software
+ libraries to compensate or QCBOR will not compile. Defining
+ QCBOR_DISABLE_FLOAT_HW_USE reduces object code size on CPUs with
+ floating-point hardware by a tiny amount.
+
+ If QCBOR_DISABLE_FLOAT_HW_USE is defined and
+ QCBOR_DISABLE_PREFERRED_FLOAT is not defined, then the only
+ functionality lost is the decoding of floating-point dates.  An error
+ will be returned if they are encountered.
+
+ If both QCBOR_DISABLE_FLOAT_HW_USE and QCBOR_DISABLE_PREFERRED_FLOAT
+ are defined, then the only thing QCBOR can do is encode/decode a
+ float as 32-bits and a double as 64-bits. Floating-point epoch dates
+ will be unsupported.
+
  Summary Limits of this implementation:
  - The entire encoded CBOR must fit into contiguous memory.
  - Max size of encoded / decoded CBOR data is @c UINT32_MAX (4GB).
@@ -443,31 +500,40 @@
 
 
 /**
- @brief  Add a floating-point number to the encoded output.
+ @brief Add a double-precision floating-point number to the encoded output.
 
  @param[in] pCtx  The encoding context to add the double to.
  @param[in] dNum  The double-precision number to add.
 
- This outputs a floating-point number with CBOR major type 7.
+ This encodes and outputs a floating-point number. CBOR major type 7
+ is used.
 
- This will selectively encode the double-precision floating-point
- number as either double-precision, single-precision or
- half-precision. It will always encode infinity, NaN and 0 has half
- precision. If no precision will be lost in the conversion to
- half-precision, then it will be converted and encoded. If not and no
- precision will be lost in conversion to single-precision, then it
- will be converted and encoded. If not, then no conversion is
- performed, and it encoded as a double.
+ This implements preferred serialization, selectively encoding the
+ double-precision floating-point number as either double-precision,
+ single-precision or half-precision. Infinity, NaN and 0 are always
+ encoded as half-precision. If no precision will be lost in the
+ conversion to half-precision, then it will be converted and
+ encoded. If not and no precision will be lost in conversion to
+ single-precision, then it will be converted and encoded. If not, then
+ no conversion is performed, and it encoded as a double-precision.
 
  Half-precision floating-point numbers take up 2 bytes, half that of
  single-precision, one quarter of double-precision
 
- This automatically reduces the size of encoded messages a lot, maybe
- even by four if most of values are 0, infinity or NaN.
+ This automatically reduces the size of encoded CBOR, maybe even by
+ four if most of values are 0, infinity or NaN.
 
- On decode, these will always be returned as a double.
+ When decoded, QCBOR will usually return these values as
+ double-precision.
+
+ It is possible to disable this preferred serialization when compiling
+ QCBOR. In that case, this functions the same as
+ QCBOREncode_AddDoubleNoPreferred().
 
  Error handling is the same as QCBOREncode_AddInt64().
+
+ See also QCBOREncode_AddDoubleNoPreferred(), QCBOREncode_AddFloat()
+ and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point.
  */
 void QCBOREncode_AddDouble(QCBOREncodeContext *pCtx, double dNum);
 
@@ -477,6 +543,68 @@
 
 
 /**
+ @brief Add a single-precision floating-point number to the encoded output.
+
+ @param[in] pCtx  The encoding context to add the double to.
+ @param[in] fNum  The single-precision number to add.
+
+ This is identical to QCBOREncode_AddDouble() except the input is
+ single-precision.
+
+ See also QCBOREncode_AddDouble(), QCBOREncode_AddDoubleNoPreferred(),
+ and QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point.
+*/
+void QCBOREncode_AddFloat(QCBOREncodeContext *pCtx, float fNum);
+
+static void QCBOREncode_AddFloatToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum);
+
+static void QCBOREncode_AddFloatToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float dNum);
+
+
+/**
+ @brief Add a double-precision floating-point number without preferred encoding.
+
+ @param[in] pCtx  The encoding context to add the double to.
+ @param[in] dNum  The double-precision number to add.
+
+ This always outputs the number as a 64-bit double-precision.
+ Preferred serialization is not used.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+
+ See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and
+ QCBOREncode_AddFloatNoPreferred() and @ref Floating-Point.
+*/
+void QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *pCtx, double dNum);
+
+static void QCBOREncode_AddDoubleNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum);
+
+static void QCBOREncode_AddDoubleNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum);
+
+
+/**
+ @brief Add a single-precision floating-point number without preferred encoding.
+
+ @param[in] pCtx  The encoding context to add the double to.
+ @param[in] fNum  The single-precision number to add.
+
+ This always outputs the number as a 32-bit single-precision.
+ Preferred serialization is not used.
+
+ Error handling is the same as QCBOREncode_AddInt64().
+
+ See also QCBOREncode_AddDouble(), QCBOREncode_AddFloat(), and
+ QCBOREncode_AddDoubleNoPreferred() and @ref Floating-Point.
+*/
+void QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *pCtx, float fNum);
+
+static void QCBOREncode_AddFloatNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, float fNum);
+
+static void QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float fNum);
+
+
+
+/**
  @brief Add an optional tag.
 
  @param[in] pCtx  The encoding context to add the tag to.
@@ -1581,6 +1709,42 @@
    QCBOREncode_AddDouble(pCtx, dNum);
 }
 
+static inline void QCBOREncode_AddFloatToMap(QCBOREncodeContext *pCtx, const char *szLabel, float dNum)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddFloat(pCtx, dNum);
+}
+
+static inline void QCBOREncode_AddFloatToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float fNum)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddFloat(pCtx, fNum);
+}
+
+static inline void QCBOREncode_AddDoubleNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, double dNum)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddDoubleNoPreferred(pCtx, dNum);
+}
+
+static inline void QCBOREncode_AddDoubleNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, double dNum)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddDoubleNoPreferred(pCtx, dNum);
+}
+
+static inline void QCBOREncode_AddFloatNoPreferredToMap(QCBOREncodeContext *pCtx, const char *szLabel, float dNum)
+{
+   QCBOREncode_AddSZString(pCtx, szLabel);
+   QCBOREncode_AddFloatNoPreferred(pCtx, dNum);
+}
+
+static inline void QCBOREncode_AddFloatNoPreferredToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, float dNum)
+{
+   QCBOREncode_AddInt64(pCtx, nLabel);
+   QCBOREncode_AddFloatNoPreferred(pCtx, dNum);
+}
+
 
 static inline void QCBOREncode_AddDateEpoch(QCBOREncodeContext *pCtx, int64_t date)
 {
diff --git a/src/ieee754.c b/src/ieee754.c
index 41f60cf..8b2efa8 100644
--- a/src/ieee754.c
+++ b/src/ieee754.c
@@ -10,6 +10,8 @@
  Created on 7/23/18
  =============================================================================*/
 
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+
 #include "ieee754.h"
 #include <string.h> // For memcpy()
 
@@ -160,13 +162,6 @@
     return u64;
 }
 
-static inline float CopyUint32ToFloat(uint32_t u32)
-{
-    float f;
-    memcpy(&f, &u32, sizeof(uint32_t));
-    return f;
-}
-
 static inline double CopyUint64ToDouble(uint64_t u64)
 {
     double d;
@@ -187,9 +182,9 @@
 
     // Now convert the three parts to half-precision.
 
-    // All works is done on uint32_t with conversion to uint16_t at the end.
-    // This avoids integer promotions that static analyzers complain about and
-    // reduces code size.
+    // All works is done on uint32_t with conversion to uint16_t at
+    // the end.  This avoids integer promotions that static analyzers
+    // complain about and reduces code size.
     uint32_t uHalfSign, uHalfSignificand, uHalfBiasedExponent;
 
     if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) {
@@ -199,38 +194,42 @@
             // Infinity
             uHalfSignificand = 0;
         } else {
-            // Copy the LSBs of the NaN payload that will fit from the single to the half
+            // Copy the LSBs of the NaN payload that will fit from the
+            // single to the half
             uHalfSignificand = uSingleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT);
             if(uSingleSignificand & SINGLE_QUIET_NAN_BIT) {
                 // It's a qNaN; copy the qNaN bit
                 uHalfSignificand |= HALF_QUIET_NAN_BIT;
             } else {
-                // It's an sNaN; make sure the significand is not zero so it stays a NaN
-                // This is needed because not all significand bits are copied from single
+                // It's an sNaN; make sure the significand is not zero
+                // so it stays a NaN This is needed because not all
+                // significand bits are copied from single
                 if(!uHalfSignificand) {
-                    // Set the LSB. This is what wikipedia shows for sNAN.
+                    // Set the LSB. This is what wikipedia shows for
+                    // sNAN.
                     uHalfSignificand |= 0x01;
                 }
             }
         }
     } else if(nSingleUnbiasedExponent == SINGLE_EXPONENT_ZERO) {
-        // 0 or a subnormal number  -- singled biased exponent is 0
+        // 0 or a subnormal number -- singled biased exponent is 0
         uHalfBiasedExponent = 0;
         uHalfSignificand    = 0; // Any subnormal single will be too small to express as a half precision
     } else if(nSingleUnbiasedExponent > HALF_EXPONENT_MAX) {
-        // Exponent is too large to express in half-precision; round up to infinity
+        // Exponent is too large to express in half-precision; round
+        // up to infinity
         uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS;
         uHalfSignificand    = 0;
     } else if(nSingleUnbiasedExponent < HALF_EXPONENT_MIN) {
-        // Exponent is too small to express in half-precision normal; make it a half-precision subnormal
+        // Exponent is too small to express in half-precision normal;
+        // make it a half-precision subnormal
         uHalfBiasedExponent = HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS;
-        // Difference between single normal exponent and the base exponent of a half subnormal
-        const uint32_t uExpDiff = (uint32_t)-(nSingleUnbiasedExponent - HALF_EXPONENT_MIN);
-        // Also have to shift the significand by the difference in number of bits between a single and a half significand
-        const uint32_t uSignificandBitsDiff = SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS;
-        // Add in the 1 that is implied in the significand of a normal number; it needs to be present in a subnormal
-        const uint32_t uSingleSignificandSubnormal = uSingleSignificand + (0x01U << SINGLE_NUM_SIGNIFICAND_BITS);
-        uHalfSignificand = uSingleSignificandSubnormal >> (uExpDiff + uSignificandBitsDiff);
+        uHalfSignificand    = 0;
+        // Could convert some of these values to a half-precision
+        // subnormal, but the layer above this will never use it. See
+        // layer above.  There is code to do this in github history
+        // for this file, but it was removed because it was never
+        // invoked.
     } else {
         // The normal case, exponent is in range for half-precision
         uHalfBiasedExponent = (uint32_t)(nSingleUnbiasedExponent + HALF_EXPONENT_BIAS);
@@ -242,8 +241,8 @@
     const uint32_t uHalfPrecision =  uHalfSignificand |
                                     (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) |
                                     (uHalfSign << HALF_SIGN_SHIFT);
-    // Cast is safe because all the masks and shifts above work to make
-    // a half precision value which is only 16 bits.
+    // Cast is safe because all the masks and shifts above work to
+    // make a half precision value which is only 16 bits.
     return (uint16_t)uHalfPrecision;
 }
 
@@ -259,11 +258,11 @@
 
     // Now convert the three parts to half-precision.
 
-    // All works is done on uint64_t with conversion to uint16_t at the end.
-    // This avoids integer promotions that static analyzers complain about.
-    // Other options are for these to be unsigned int or fast_int16_t. Code
-    // size doesn't vary much between all these options for 64-bit LLVM,
-    // 64-bit GCC and 32-bit Armv7 LLVM.
+    // All works is done on uint64_t with conversion to uint16_t at
+    // the end.  This avoids integer promotions that static analyzers
+    // complain about.  Other options are for these to be unsigned int
+    // or fast_int16_t. Code size doesn't vary much between all these
+    // options for 64-bit LLVM, 64-bit GCC and 32-bit Armv7 LLVM.
     uint64_t uHalfSign, uHalfSignificand, uHalfBiasedExponent;
 
     if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) {
@@ -273,38 +272,42 @@
             // Infinity
             uHalfSignificand = 0;
         } else {
-            // Copy the LSBs of the NaN payload that will fit from the double to the half
+            // Copy the LSBs of the NaN payload that will fit from the
+            // double to the half
             uHalfSignificand = uDoubleSignificand & (HALF_SIGNIFICAND_MASK & ~HALF_QUIET_NAN_BIT);
             if(uDoubleSignificand & DOUBLE_QUIET_NAN_BIT) {
                 // It's a qNaN; copy the qNaN bit
                 uHalfSignificand |= HALF_QUIET_NAN_BIT;
             } else {
-                // It's an sNaN; make sure the significand is not zero so it stays a NaN
-                // This is needed because not all significand bits are copied from single
+                // It's an sNaN; make sure the significand is not zero
+                // so it stays a NaN This is needed because not all
+                // significand bits are copied from single
                 if(!uHalfSignificand) {
-                    // Set the LSB. This is what wikipedia shows for sNAN.
+                    // Set the LSB. This is what wikipedia shows for
+                    // sNAN.
                     uHalfSignificand |= 0x01;
                 }
             }
         }
     } else if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_ZERO) {
-        // 0 or a subnormal number  -- double biased exponent is 0
+        // 0 or a subnormal number -- double biased exponent is 0
         uHalfBiasedExponent = 0;
         uHalfSignificand    = 0; // Any subnormal single will be too small to express as a half precision; TODO, is this really true?
     } else if(nDoubleUnbiasedExponent > HALF_EXPONENT_MAX) {
-        // Exponent is too large to express in half-precision; round up to infinity; TODO, is this really true?
+        // Exponent is too large to express in half-precision; round
+        // up to infinity; TODO, is this really true?
         uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS;
         uHalfSignificand    = 0;
     } else if(nDoubleUnbiasedExponent < HALF_EXPONENT_MIN) {
-        // Exponent is too small to express in half-precision; round down to zero
+        // Exponent is too small to express in half-precision; round
+        // down to zero
         uHalfBiasedExponent = HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS;
-        // Difference between double normal exponent and the base exponent of a half subnormal
-        const uint64_t uExpDiff = (uint64_t)-(nDoubleUnbiasedExponent - HALF_EXPONENT_MIN);
-        // Also have to shift the significand by the difference in number of bits between a double and a half significand
-        const uint64_t uSignificandBitsDiff = DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS;
-        // Add in the 1 that is implied in the significand of a normal number; it needs to be present in a subnormal
-        const uint64_t uDoubleSignificandSubnormal = uDoubleSignificand + (0x01ULL << DOUBLE_NUM_SIGNIFICAND_BITS);
-        uHalfSignificand = uDoubleSignificandSubnormal >> (uExpDiff + uSignificandBitsDiff);
+        uHalfSignificand = 0;
+        // Could convert some of these values to a half-precision
+        // subnormal, but the layer above this will never use it. See
+        // layer above.  There is code to do this in github history
+        // for this file, but it was removed because it was never
+        // invoked.
     } else {
         // The normal case, exponent is in range for half-precision
         uHalfBiasedExponent = (uint32_t)(nDoubleUnbiasedExponent + HALF_EXPONENT_BIAS);
@@ -317,82 +320,25 @@
     const uint64_t uHalfPrecision =  uHalfSignificand |
                                     (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) |
                                     (uHalfSign << HALF_SIGN_SHIFT);
-    // Cast is safe because all the masks and shifts above work to make
-    // a half precision value which is only 16 bits.
+    // Cast is safe because all the masks and shifts above work to
+    // make a half precision value which is only 16 bits.
     return (uint16_t)uHalfPrecision;
 }
 
 
-
-// Public function; see ieee754.h
-float IEEE754_HalfToFloat(uint16_t uHalfPrecision)
-{
-    // Pull out the three parts of the half-precision float
-    // Do all the work in 32 bits because that is what the end result is
-    // may give smaller code size and will keep static analyzers happier.
-    const uint32_t uHalfSignificand      = uHalfPrecision & HALF_SIGNIFICAND_MASK;
-    const int32_t  nHalfUnBiasedExponent = (int32_t)((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS;
-    const uint32_t uHalfSign             = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT;
-
-
-    // Make the three parts of the single-precision number
-    uint32_t uSingleSignificand, uSingleSign, uSingleBiasedExponent;
-    if(nHalfUnBiasedExponent == HALF_EXPONENT_ZERO) {
-        // 0 or subnormal
-        if(uHalfSignificand) {
-            // Subnormal case
-            uSingleBiasedExponent = -HALF_EXPONENT_BIAS + SINGLE_EXPONENT_BIAS +1;
-            // A half-precision subnormal can always be converted to a normal single-precision float because the ranges line up
-            uSingleSignificand = uHalfSignificand;
-            // Shift bits from right of the decimal to left, reducing the exponent by 1 each time
-            do {
-                uSingleSignificand <<= 1;
-                uSingleBiasedExponent--;
-            } while ((uSingleSignificand & 0x400) == 0);
-            uSingleSignificand &= HALF_SIGNIFICAND_MASK;
-            uSingleSignificand <<= (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
-        } else {
-            // Just zero
-            uSingleBiasedExponent = SINGLE_EXPONENT_ZERO + SINGLE_EXPONENT_BIAS;
-            uSingleSignificand = 0;
-        }
-    } else if(nHalfUnBiasedExponent == HALF_EXPONENT_INF_OR_NAN) {
-        // NaN or Inifinity
-        uSingleBiasedExponent = SINGLE_EXPONENT_INF_OR_NAN + SINGLE_EXPONENT_BIAS;
-        if(uHalfSignificand) {
-            // NaN
-            // First preserve the NaN payload from half to single
-            uSingleSignificand = uHalfSignificand & ~HALF_QUIET_NAN_BIT;
-            if(uHalfSignificand & HALF_QUIET_NAN_BIT) {
-                // Next, set qNaN if needed since half qNaN bit is not copied above
-                uSingleSignificand |= SINGLE_QUIET_NAN_BIT;
-            }
-        } else {
-            // Infinity
-            uSingleSignificand = 0;
-        }
-    } else {
-        // Normal number
-        uSingleBiasedExponent = (uint32_t)(nHalfUnBiasedExponent + SINGLE_EXPONENT_BIAS);
-        uSingleSignificand = uHalfSignificand << (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
-    }
-    uSingleSign = uHalfSign;
-
-    // Shift the three parts of the single-precision into place
-    const uint32_t uSinglePrecision = uSingleSignificand |
-                                     (uSingleBiasedExponent << SINGLE_EXPONENT_SHIFT) |
-                                     (uSingleSign << SINGLE_SIGN_SHIFT);
-
-    return CopyUint32ToFloat(uSinglePrecision);
-}
+/*
+  EEE754_HalfToFloat() was created but is not needed. It can be retrieved from
+  github history if needed.
+ */
 
 
 // Public function; see ieee754.h
 double IEEE754_HalfToDouble(uint16_t uHalfPrecision)
 {
-    // Pull out the three parts of the half-precision float
-    // Do all the work in 64 bits because that is what the end result is
-    // may give smaller code size and will keep static analyzers happier.
+    // Pull out the three parts of the half-precision float.  Do all
+    // the work in 64 bits because that is what the end result is.  It
+    // may give smaller code size and will keep static analyzers
+    // happier.
     const uint64_t uHalfSignificand      = uHalfPrecision & HALF_SIGNIFICAND_MASK;
     const int64_t  nHalfUnBiasedExponent = (int64_t)((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS;
     const uint64_t uHalfSign             = (uHalfPrecision & HALF_SIGN_MASK) >> HALF_SIGN_SHIFT;
@@ -406,9 +352,12 @@
         if(uHalfSignificand) {
             // Subnormal case
             uDoubleBiasedExponent = -HALF_EXPONENT_BIAS + DOUBLE_EXPONENT_BIAS +1;
-            // A half-precision subnormal can always be converted to a normal double-precision float because the ranges line up
+            // A half-precision subnormal can always be converted to a
+            // normal double-precision float because the ranges line
+            // up
             uDoubleSignificand = uHalfSignificand;
-            // Shift bits from right of the decimal to left, reducing the exponent by 1 each time
+            // Shift bits from right of the decimal to left, reducing
+            // the exponent by 1 each time
             do {
                 uDoubleSignificand <<= 1;
                 uDoubleBiasedExponent--;
@@ -427,7 +376,8 @@
             // First preserve the NaN payload from half to single
             uDoubleSignificand = uHalfSignificand & ~HALF_QUIET_NAN_BIT;
             if(uHalfSignificand & HALF_QUIET_NAN_BIT) {
-                // Next, set qNaN if needed since half qNaN bit is not copied above
+                // Next, set qNaN if needed since half qNaN bit is not
+                // copied above
                 uDoubleSignificand |= DOUBLE_QUIET_NAN_BIT;
             }
         } else {
@@ -451,6 +401,77 @@
 
 
 // Public function; see ieee754.h
+double IEEE754_FloatToDouble(uint32_t uFloat)
+{
+    // Pull out the three parts of the single-precision float.  Do all
+    // the work in 64 bits because that is what the end result is.  It
+    // may give smaller code size and will keep static analyzers
+    // happier.
+    const uint64_t uSingleSignificand      = uFloat & SINGLE_SIGNIFICAND_MASK;
+    const int64_t  nSingleUnBiasedExponent = (int64_t)((uFloat & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS;
+    const uint64_t uSingleSign             = (uFloat & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT;
+
+
+    // Make the three parts of hte single-precision number
+    uint64_t uDoubleSignificand, uDoubleSign, uDoubleBiasedExponent;
+    if(nSingleUnBiasedExponent == SINGLE_EXPONENT_ZERO) {
+        // 0 or subnormal
+        uDoubleBiasedExponent = DOUBLE_EXPONENT_ZERO + DOUBLE_EXPONENT_BIAS;
+        if(uSingleSignificand) {
+            // Subnormal case
+            uDoubleBiasedExponent = -SINGLE_EXPONENT_BIAS + DOUBLE_EXPONENT_BIAS + 1;
+            // A single-precision subnormal can always be converted to
+            // a normal double-precision float because the ranges line
+            // up
+            uDoubleSignificand = uSingleSignificand;
+            // Shift bits from right of the decimal to left, reducing
+            // the exponent by 1 each time
+            do {
+                uDoubleSignificand <<= 1;
+                uDoubleBiasedExponent--;
+                // TODO: is this right? Where does 0x400 come from?
+            } while ((uDoubleSignificand & 0x400) == 0);
+            uDoubleSignificand &= SINGLE_SIGNIFICAND_MASK;
+            uDoubleSignificand <<= (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS);
+        } else {
+            // Just zero
+            uDoubleSignificand = 0;
+        }
+    } else if(nSingleUnBiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) {
+        // NaN or Inifinity
+        uDoubleBiasedExponent = DOUBLE_EXPONENT_INF_OR_NAN + DOUBLE_EXPONENT_BIAS;
+        if(uSingleSignificand) {
+            // NaN
+            // First preserve the NaN payload from half to single
+            // TODO: check this
+            uDoubleSignificand = uSingleSignificand & ~SINGLE_QUIET_NAN_BIT;
+            if(uSingleSignificand & SINGLE_QUIET_NAN_BIT) {
+                // Next, set qNaN if needed since half qNaN bit is not copied above
+                uDoubleSignificand |= DOUBLE_QUIET_NAN_BIT;
+            }
+        } else {
+            // Infinity
+            uDoubleSignificand = 0;
+        }
+    } else {
+        // Normal number
+        uDoubleBiasedExponent = (uint64_t)(nSingleUnBiasedExponent + DOUBLE_EXPONENT_BIAS);
+        uDoubleSignificand    = uSingleSignificand << (DOUBLE_NUM_SIGNIFICAND_BITS - SINGLE_NUM_SIGNIFICAND_BITS);
+    }
+    uDoubleSign = uSingleSign;
+
+
+    // Shift the 3 parts into place as a double-precision
+    const uint64_t uDouble = uDoubleSignificand |
+                            (uDoubleBiasedExponent << DOUBLE_EXPONENT_SHIFT) |
+                            (uDoubleSign << DOUBLE_SIGN_SHIFT);
+    return CopyUint64ToDouble(uDouble);
+}
+
+
+
+
+// Public function; see ieee754.h
 IEEE754_union IEEE754_FloatToSmallest(float f)
 {
     IEEE754_union result;
@@ -460,11 +481,12 @@
     const int32_t  nSingleExponent    = (int32_t)((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS;
     const uint32_t uSingleSignificand =   uSingle & SINGLE_SIGNIFICAND_MASK;
 
-    // Bit mask that is the significand bits that would be lost when converting
-    // from single-precision to half-precision
+    // Bit mask that is the significand bits that would be lost when
+    // converting from single-precision to half-precision
     const uint64_t uDroppedSingleBits = SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS;
 
-    // Optimizer will re organize so there is only one call to IEEE754_FloatToHalf()
+    // Optimizer will re organize so there is only one call to
+    // IEEE754_FloatToHalf() in the final code.
     if(uSingle == 0) {
         // Value is 0.0000, not a a subnormal
         result.uSize = IEEE754_UNION_IS_HALF;
@@ -494,12 +516,18 @@
     // Pull the needed two parts out of the double-precision float
     const uint64_t uDouble = CopyDoubleToUint64(d);
     const int64_t  nDoubleExponent     = (int64_t)((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS;
-    const uint64_t uDoubleSignificand  =   uDouble & DOUBLE_SIGNIFICAND_MASK;
+    const uint64_t uDoubleSignificand  = uDouble & DOUBLE_SIGNIFICAND_MASK;
 
     // Masks to check whether dropped significand bits are zero or not
-    const uint64_t uDroppedDoubleBits = DOUBLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS;
+    const uint64_t uDroppedHalfBits = DOUBLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS;
     const uint64_t uDroppedSingleBits = DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS;
 
+    // This will not convert to half-precion or single-precision
+    // subnormals.  Values that could be converted will be output as
+    // the double they are or occasionally to a normal single.  This
+    // could be implemented, but it is more code and would rarely be
+    // used and rarely reduce the output size.
+
     // The various cases
     if(d == 0.0) { // Take care of positive and negative zero
         // Value is 0.0000, not a a subnormal
@@ -509,7 +537,7 @@
         // NaN, +/- infinity
         result.uSize  = IEEE754_UNION_IS_HALF;
         result.uValue = IEEE754_DoubleToHalf(d);
-    } else if(bAllowHalfPrecision && (nDoubleExponent >= HALF_EXPONENT_MIN) && nDoubleExponent <= HALF_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedDoubleBits))) {
+    } else if(bAllowHalfPrecision && (nDoubleExponent >= HALF_EXPONENT_MIN) && nDoubleExponent <= HALF_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedHalfBits))) {
         // Can convert to half without precision loss
         result.uSize  = IEEE754_UNION_IS_HALF;
         result.uValue = IEEE754_DoubleToHalf(d);
@@ -526,3 +554,8 @@
     return result;
 }
 
+#else
+
+int x;
+
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
diff --git a/src/ieee754.h b/src/ieee754.h
index 705ef62..d614825 100644
--- a/src/ieee754.h
+++ b/src/ieee754.h
@@ -10,6 +10,8 @@
  Created on 7/23/18
  =============================================================================*/
 
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+
 #ifndef ieee754_h
 #define ieee754_h
 
@@ -75,13 +77,6 @@
 
 
 /*
- Convert half-precision float to single-precision float.  This is a
- loss-less conversion.
- */
-float IEEE754_HalfToFloat(uint16_t uHalfPrecision);
-
-
-/*
  Convert double-precision float to half-precision float.  Precision
  and NaN payload bits will be lost. Too-large values will round up to
  infinity and too small to zero.
@@ -96,6 +91,13 @@
 double IEEE754_HalfToDouble(uint16_t uHalfPrecision);
 
 
+/*
+ Convert float to double-precision without using any
+ floating-point HW or compiler-supplied SW.
+ This is a loss-less conversion.
+ */
+double IEEE754_FloatToDouble(uint32_t ufloat);
+
 
 // Both tags the value and gives the size
 #define IEEE754_UNION_IS_HALF   2
@@ -146,7 +148,7 @@
 #endif /* ieee754_h */
 
 
-
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
 
 
 
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 094a0c1..b5140c1 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -796,12 +796,25 @@
       // caught before this is called.
 
       case HALF_PREC_FLOAT:
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+         // The cast to uint16_t is safe because the encoded value
+         // was 16 bits. It was widened to 64 bits to be passed in here.
          pDecodedItem->val.dfnum = IEEE754_HalfToDouble((uint16_t)uNumber);
          pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
+#else
+         nReturn = QCBOR_ERR_HALF_PRECISION_UNSUPPORTED;
+#endif
          break;
       case SINGLE_PREC_FLOAT:
-         pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+         // The cast to uint32_t is safe because the encoded value
+         // was 32 bits. It was widened to 64 bits to be passed in here.
+         pDecodedItem->val.dfnum = IEEE754_FloatToDouble((uint32_t)uNumber);
          pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
+#else
+         pDecodedItem->val.fnum = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
+         pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
+#endif
          break;
       case DOUBLE_PREC_FLOAT:
          pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
@@ -1537,37 +1550,52 @@
          break;
 
       case QCBOR_TYPE_DOUBLE:
+      case QCBOR_TYPE_FLOAT:
+#ifndef QCBOR_DISABLE_FLOAT_HW_USE
       {
          // This comparison needs to be done as a float before
-         // conversion to an int64_t to be able to detect doubles
-         // that are too large to fit into an int64_t.  A double
-         // has 52 bits of preceision. An int64_t has 63. Casting
-         // INT64_MAX to a double actually causes a round up which
-         // is bad and wrong for the comparison because it will
-         // allow conversion of doubles that can't fit into a
-         // uint64_t.  To remedy this INT64_MAX - 0x7ff is used as
-         // the cutoff point as if that rounds up in conversion to
-         // double it will still be less than INT64_MAX. 0x7ff is
-         // picked because it has 11 bits set.
+         // conversion to an int64_t to be able to detect doubles that
+         // are too large to fit into an int64_t.  A double has 52
+         // bits of preceision. An int64_t has 63. Casting INT64_MAX
+         // to a double actually causes a round up which is bad and
+         // wrong for the comparison because it will allow conversion
+         // of doubles that can't fit into a uint64_t.  To remedy this
+         // INT64_MAX - 0x7ff is used as the cutoff point because if
+         // that value rounds up in conversion to double it will still
+         // be less than INT64_MAX. 0x7ff is picked because it has 11
+         // bits set.
          //
-         // INT64_MAX seconds is on the order of 10 billion years,
-         // and the earth is less than 5 billion years old, so for
-         // most uses this conversion error won't occur even though
-         // doubles can go much larger.
+         // INT64_MAX seconds is on the order of 10 billion years, and
+         // the earth is less than 5 billion years old, so for most
+         // uses this conversion error won't occur even though doubles
+         // can go much larger.
          //
          // Without the 0x7ff there is a ~30 minute range of time
          // values 10 billion years in the past and in the future
-         // where this this code would go wrong.
-         const double d = pDecodedItem->val.dfnum;
+         // where this this code would go wrong and some compilers
+         // will generate warnings or errors.
+         const double d = pDecodedItem->uDataType == QCBOR_TYPE_DOUBLE ?
+                            pDecodedItem->val.dfnum :
+                            (double)pDecodedItem->val.fnum;
          if(d > (double)(INT64_MAX - 0x7ff)) {
             nReturn = QCBOR_ERR_DATE_OVERFLOW;
             goto Done;
          }
          pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
-         pDecodedItem->val.epochDate.fSecondsFraction = d - (double)pDecodedItem->val.epochDate.nSeconds;
+         pDecodedItem->val.epochDate.fSecondsFraction =
+                           d - (double)pDecodedItem->val.epochDate.nSeconds;
       }
+#else
+         /* Disabling float support causes a floating point
+          data to error in the default below. The above code
+          requires floating point conversion to integers and
+          comparison which requires either floating point HW
+          or a SW library. */
+         nReturn = QCBOR_ERR_FLOAT_DATE_UNSUPPORTED;
+#endif /* QCBOR_DISABLE_FLOAT_HW_USE */
          break;
 
+
       default:
          nReturn = QCBOR_ERR_BAD_OPT_TAG;
          goto Done;
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index b17698d..08de596 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -577,12 +577,53 @@
 
 /*
  Public functions for adding a double. See qcbor/qcbor_encode.h
+*/
+void QCBOREncode_AddDoubleNoPreferred(QCBOREncodeContext *me, double dNum)
+{
+   QCBOREncode_AddType7(me,
+                        sizeof(uint64_t),
+                        UsefulBufUtil_CopyDoubleToUint64(dNum));
+}
+
+
+/*
+ Public functions for adding a double. See qcbor/qcbor_encode.h
  */
 void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
 {
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
    const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
 
    QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
+#else
+   QCBOREncode_AddDoubleNoPreferred(me, dNum);
+#endif
+}
+
+
+/*
+ Public functions for adding a float. See qcbor/qcbor_encode.h
+*/
+void QCBOREncode_AddFloatNoPreferred(QCBOREncodeContext *me, float fNum)
+{
+   QCBOREncode_AddType7(me,
+                        sizeof(uint32_t),
+                        UsefulBufUtil_CopyFloatToUint32(fNum));
+}
+
+
+/*
+ Public functions for adding a float. See qcbor/qcbor_encode.h
+ */
+void QCBOREncode_AddFloat(QCBOREncodeContext *me, float fNum)
+{
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+   const IEEE754_union uNum = IEEE754_FloatToSmallest(fNum);
+
+   QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
+#else
+   QCBOREncode_AddFloatNoPreferred(me, fNum);
+#endif
 }
 
 
diff --git a/test/float_tests.c b/test/float_tests.c
index e7696d1..5aefaea 100644
--- a/test/float_tests.c
+++ b/test/float_tests.c
@@ -10,56 +10,81 @@
  Created on 9/19/18
  =============================================================================*/
 
+
 #include "float_tests.h"
 #include "qcbor/qcbor_encode.h"
 #include "qcbor/qcbor_decode.h"
-#include "half_to_double_from_rfc7049.h"
 #include <math.h> // For INFINITY and NAN and isnan()
 
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+
+#include "half_to_double_from_rfc7049.h"
 
 
+/*
+ Half-precision values that are input to test half-precision decoding
+
+ As decoded by http://cbor.me
+ {"zero": 0.0,
+ "infinitity": Infinity,
+ "negative infinitity": -Infinity,
+ "NaN": NaN,
+ "one": 1.0,
+ "one third": 0.333251953125,
+ "largest half-precision": 65504.0,
+ "too-large half-precision": Infinity,
+ "smallest subnormal": 5.960464477539063e-8,
+ "smallest normal": 0.00006097555160522461,
+ "biggest subnormal": 0.00006103515625,
+ "subnormal single": 0.0,
+ 3: -2.0,
+ 4: NaN,
+ 5: NaN,
+ 6: NaN,
+ 7: NaN}
+ */
 static const uint8_t spExpectedHalf[] = {
     0xB1,
         0x64,
             0x7A, 0x65, 0x72, 0x6F,
-        0xF9, 0x00, 0x00,   // 0.000
+        0xF9, 0x00, 0x00, // half-precision 0.000
         0x6A,
             0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
-        0xF9, 0x7C, 0x00,   // Infinity
+        0xF9, 0x7C, 0x00, // Infinity
         0x73,
             0x6E, 0x65, 0x67, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6E,
             0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
-        0xF9, 0xFC, 0x00,   // -Inifinity
+        0xF9, 0xFC, 0x00, // -Inifinity
         0x63,
             0x4E, 0x61, 0x4E,
-        0xF9, 0x7E, 0x00,   // NaN
+        0xF9, 0x7E, 0x00, // NaN
         0x63,
             0x6F, 0x6E, 0x65,
-        0xF9, 0x3C, 0x00,   // 1.0
+        0xF9, 0x3C, 0x00, // 1.0
         0x69,
             0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64,
-        0xF9, 0x35, 0x55,   // 0.333251953125
+        0xF9, 0x35, 0x55, // half-precsion one third 0.333251953125
         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,   // 65504.0
+        0xF9, 0x7B, 0xFF, // largest half-precision 65504.0
         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,
-        0xF9, 0x7C, 0x00,   // Infinity
+        0xF9, 0x7C, 0x00, // Infinity
         0x72,
             0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75,
             0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
-        0xF9, 0x00, 0x01,   // 0.000000059604
-        0x6F,
-            0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F,
-            0x72, 0x6D, 0x61, 0x6C,
-        0xF9, 0x03, 0xFF,   // 0.0000609755516
+        0xF9, 0x00, 0x01, // Smallest half-precision subnormal 0.000000059604645
         0x71,
             0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62,
             0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
-        0xF9, 0x04, 0x00,   // 0.000061988
+        0xF9, 0x03, 0xFF, // Largest half-precision subnormal 0.0000609755516
+        0x6F,
+            0x73, 0x6D, 0x61, 0x6C, 0x6C, 0x65, 0x73, 0x74, 0x20, 0x6E, 0x6F,
+            0x72, 0x6D, 0x61, 0x6C,
+        0xF9, 0x04, 0x00,  // Smallest half-precision normal 0.000061988
         0x70,
             0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73,
             0x69, 0x6E, 0x67, 0x6C, 0x65,
@@ -74,118 +99,130 @@
         0xF9, 0x7E, 0x0F,    // qNaN with payload 0x0f
         0x07,
         0xF9, 0x7C, 0x0F,    // sNaN with payload 0x0f
-
 };
 
 
+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);
+   UsefulBufC HalfPrecision = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedHalf);
 
-    QCBORDecodeContext DC;
-    QCBORDecode_Init(&DC, HalfPrecision, 0);
+   QCBORDecodeContext DC;
+   QCBORDecode_Init(&DC, HalfPrecision, 0);
 
-    QCBORItem Item;
+   QCBORItem Item;
 
-    QCBORDecode_GetNext(&DC, &Item);
-    if(Item.uDataType != QCBOR_TYPE_MAP) {
-        return -1;
-    }
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_MAP) {
+      return -1;
+   }
 
-    QCBORDecode_GetNext(&DC, &Item);
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0F) {
-        return -2;
-    }
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0) {
+      return -2;
+   }
 
-    QCBORDecode_GetNext(&DC, &Item);
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
-        return -3;
-    }
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
+      return -3;
+   }
 
-    QCBORDecode_GetNext(&DC, &Item);
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -INFINITY) {
-        return -4;
-    }
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -INFINITY) {
+      return -4;
+   }
 
-    // TODO, 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;
-    }
+   // 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;
+   }
 
-    QCBORDecode_GetNext(&DC, &Item);
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 1.0F) {
-        return -6;
-    }
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 1.0) {
+      return -6;
+   }
 
-    QCBORDecode_GetNext(&DC, &Item);
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.333251953125F) {
-        return -7;
-    }
+   // Approximately 1/3
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.333251953125) {
+      return -7;
+   }
 
-    QCBORDecode_GetNext(&DC, &Item);
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 65504.0F) {
-        return -8;
-    }
+   // Largest half-precision
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 65504.0) {
+      return -8;
+   }
 
-    QCBORDecode_GetNext(&DC, &Item);
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
-        return -9;
-    }
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != INFINITY) {
+      return -9;
+   }
 
-    QCBORDecode_GetNext(&DC, &Item); // TODO: check this
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000000596046448F) {
-        return -10;
-    }
+   // Smallest half-precision subnormal
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00000005960464477539063) {
+      return -10;
+   }
 
-    QCBORDecode_GetNext(&DC, &Item); // TODO: check this
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000609755516F) {
-        return -11;
-    }
+   // Largest half-precision subnormal
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00006097555160522461) {
+      return -11;
+   }
 
-    QCBORDecode_GetNext(&DC, &Item); // TODO check this
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0000610351563F) {
-        return -12;
-    }
+   // Smallest half-precision normal
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.00006103515625) {
+      return -12;
+   }
 
-    QCBORDecode_GetNext(&DC, &Item);
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0) {
-        return -13;
-    }
+   // half-precision zero
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != 0.0) {
+      return -13;
+   }
 
-    QCBORDecode_GetNext(&DC, &Item);
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -2.0F) {
-        return -14;
-    }
+   // negative 2
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE || Item.val.dfnum != -2.0) {
+      return -14;
+   }
 
-    // TODO: double check these four tests
-    QCBORDecode_GetNext(&DC, &Item); // qNaN
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
-       UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff8000000000000ULL) {
-        return -15;
-    }
-    QCBORDecode_GetNext(&DC, &Item); // sNaN
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
-       UsefulBufUtil_CopyDoubleToUint64(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) {
-        return -17;
-    }
-    QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f
-    if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
-       UsefulBufUtil_CopyDoubleToUint64(Item.val.dfnum) != 0x7ff000000000000fULL) {
-        return -18;
-    }
+   // TODO: NAN-related double check these four tests
+   QCBORDecode_GetNext(&DC, &Item); // qNaN
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      CheckDouble(Item.val.dfnum, 0x7ff8000000000000ULL)) {
+      return -15;
+   }
+   QCBORDecode_GetNext(&DC, &Item); // sNaN
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      CheckDouble(Item.val.dfnum, 0x7ff0000000000001ULL)) {
+      return -16;
+   }
+   QCBORDecode_GetNext(&DC, &Item); // qNaN with payload 0x0f
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      CheckDouble(Item.val.dfnum, 0x7ff800000000000fULL)) {
+      return -17;
+   }
+   QCBORDecode_GetNext(&DC, &Item); // sNaN with payload 0x0f
+   if(Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      CheckDouble(Item.val.dfnum, 0x7ff000000000000fULL)) {
+      return -18;
+   }
 
-    if(QCBORDecode_Finish(&DC)) {
-        return -19;
-    }
+   if(QCBORDecode_Finish(&DC)) {
+      return -19;
+   }
 
-    return 0;
+   return 0;
 }
 
 
@@ -241,210 +278,601 @@
 
 
 /*
- {"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"}
  */
 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_AddDoubleAsSmallestToMap QCBOREncode_AddDoubleToMap
-#define QCBOREncode_AddDoubleAsSmallestToMapN QCBOREncode_AddDoubleToMapN
+   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
+
+   // F9 0000                              # primitive(0)
+   QCBOREncode_AddDoubleToMap(&EC, "zero", 0.00);
+
+   // F9 8000                              # primitive(0)
+   QCBOREncode_AddDoubleToMap(&EC, "negative zero", -0.00);
+
+   // F9 7C00                              # primitive(31744)
+   QCBOREncode_AddDoubleToMap(&EC, "infinitity", INFINITY);
+
+   // F9 FC00                              # primitive(64512)
+   QCBOREncode_AddDoubleToMap(&EC, "negative infinitity", -INFINITY);
+
+   // F9 7E00                              # primitive(32256)
+   QCBOREncode_AddDoubleToMap(&EC, "NaN", NAN);
+
+   // TODO: test a few NaN variants
+
+   // F9 3C00                              # primitive(15360)
+   QCBOREncode_AddDoubleToMap(&EC, "one", 1.0);
+
+   // F9 3555                              # primitive(13653)
+   QCBOREncode_AddDoubleToMap(&EC, "one third", 0.333251953125);
+
+   // 65504.0, converts to the large possible half-precision.
+   // 0xF9, 0x7B, 0xFF,
+   QCBOREncode_AddDoubleToMap(&EC, "largest half-precision", 65504.0);
+
+   // 65504.1, the double that has both to large an exponent and too
+   // much precision, so no conversion.
+   // 0xFB, 0x40, 0xEF, 0xFC, 0x03, 0x33, 0x33, 0x33, 0x33,
+   QCBOREncode_AddDoubleToMap(&EC, "largest half-precision point one", 65504.1);
+
+   // 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.
+   // 0xFA, 0x47, 0x80, 0x00, 0x00,
+   QCBOREncode_AddDoubleToMap(&EC, "too-large half-precision", 65536.0);
+
+   // 5.9604644775390625E-8, the smallest possible half-precision
+   // subnormal, digitis are lost converting to half, but not
+   // when converting to a single
+   // 0xFA, 0x33, 0x80, 0x00, 0x00,
+   QCBOREncode_AddDoubleToMap(&EC,
+                              "smallest half subnormal",
+                              MAKE_DOUBLE(0x3e70000000000000));
+
+   // 0.00006103515625, the double value that converts to the smallest
+   // possible half-precision normal.  which is what should appear in
+   // the output.
+   // 0xF9, 0x04, 0x00,
+   QCBOREncode_AddDoubleToMap(&EC,
+                              "smallest half normal",
+                              MAKE_DOUBLE(0x3f10000000000000));
+
+   // 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.
+   // 0xFB, 0x3F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+   QCBOREncode_AddDoubleToMap(&EC,
+                              "smallest half normal plus",
+                              MAKE_DOUBLE(0x3f10000000000001));
+
+   // 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.
+   // 0xFB, 0x3F, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+   QCBOREncode_AddDoubleToMap(&EC,
+                              "smallest normal minus",
+                              MAKE_DOUBLE(0x3f0fffffffffffff));
+
+   // 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.
+   // 0xFA, 0x38, 0x00, 0x00, 0x00,
+   QCBOREncode_AddDoubleToMap(&EC,
+                              "smallest normal minus",
+                              MAKE_DOUBLE(0x3f00000000000000));
+
+   // 3.4028234664e38, the value that converts to the largest possible
+   // single-precision.
+   // 0xFA, 0x7F, 0x7F, 0xFF, 0xFF,
+   QCBOREncode_AddDoubleToMap(&EC,
+                              "largest single",
+                              MAKE_DOUBLE(0x47efffffe0000000));
+
+   // 3.402823466385289E38, sightly larger than the largest possible
+   // possible precision.  Conversion fails because precision would be
+   // lost.
+   // 0xFB, 0x47, 0xEF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x01,
+   QCBOREncode_AddDoubleToMap(&EC,
+                              "largest single plus",
+                              MAKE_DOUBLE(0x47efffffe0000001));
+
+   // 6.8056469327705772E38, slightly more larger than the largers
+   // possible single precision.  Conversion fails because exponent is
+   // too large.
+   // 0xFB, 0x47, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00,
+   QCBOREncode_AddDoubleToMap(&EC,
+                              "largest single plus",
+                              MAKE_DOUBLE(0x47ffffffe0000000));
+
+   // 1.1754943508222875E-38, The double value that converts to the
+   // smallest possible single-precision normal
+   // 0xFA, 0x00, 0x80, 0x00, 0x00,
+   QCBOREncode_AddDoubleToMap(&EC,
+                              "smallest single",
+                              MAKE_DOUBLE(0x3810000000000000));
+
+   // 1.1754943508222878E-38, double value that is slightly larger
+   // than the smallest single-precision normal. Conversion fails
+   // because of precision
+   // 0xFB, 0x38, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
+   QCBOREncode_AddDoubleToMap(&EC,
+                              "smallest single plus",
+                              MAKE_DOUBLE(0x3810000000000001));
+
+   // 1.1754943508222874E-38, slightly smaller than the smallest
+   // single-precision normal.  Conversion fails because of precision
+   // 0xFB, 0x38, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+   QCBOREncode_AddDoubleToMap(&EC,
+                              "smallest single minus",
+                              MAKE_DOUBLE(0x380fffffffffffff));
+
+   // 5.8774717541114375E-39, slightly smaller than the smallest
+   // single-precision normal.  Conversion fails because the exponent
+   // is too small.
+   // 0xFB, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+   QCBOREncode_AddDoubleToMap(&EC,
+                              "smallest single minus more",
+                              MAKE_DOUBLE(0x3800000000000000));
+
+   // Just -2, which converts to a negative half-precision
+   // F9 C000                              # primitive(49152)
+   QCBOREncode_AddDoubleToMapN(&EC, 3, -2.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.
+   // 0xFB, 0x41, 0x70, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00,
+   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 */
 
 
-    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_AddDoubleAsSmallestToMap(&EC, "zero", 0.00);
+/*
+[0.0, 3.14, 0.0, NaN, Infinity, 0.0, 3.140000104904175, 0.0, NaN, Infinity,
+ {100: 0.0, 101: 3.1415926, "euler": 2.718281828459045, 105: 0.0,
+  102: 0.0, 103: 3.141592502593994, "euler2": 2.7182817459106445, 106: 0.0}]
+ */
+static const uint8_t spExpectedFloats[] = {
+   0x8B,
+      0xF9, 0x00, 0x00,
+      0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
+      0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xF9, 0x00, 0x00,
+      0xFA, 0x40, 0x48, 0xF5, 0xC3,
+      0xFA, 0x00, 0x00, 0x00, 0x00,
+      0xFA, 0x7F, 0xC0, 0x00, 0x00,
+      0xFA, 0x7F, 0x80, 0x00, 0x00,
+      0xA8,
+         0x18, 0x64,
+          0xF9, 0x00, 0x00,
+         0x18, 0x65,
+          0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
+         0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
+          0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
+         0x18, 0x69,
+          0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x18, 0x66,
+          0xF9, 0x00, 0x00,
+         0x18, 0x67,
+          0xFA, 0x40, 0x49, 0x0F, 0xDA,
+         0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
+          0xFA, 0x40, 0x2D, 0xF8, 0x54,
+         0x18, 0x6A,
+          0xFA, 0x00, 0x00, 0x00, 0x00};
 
-    // 64                                   # text(4)
-    //    7A65726F                          # "negative zero"
-    // F9 8000                              # primitive(0)
-    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative zero", -0.00);
+static const uint8_t spExpectedFloatsNoHalf[] = {
+   0x8B,
+      0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F,
+      0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xFB, 0x7F, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xFB, 0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+      0xFA, 0x00, 0x00, 0x00, 0x00,
+      0xFA, 0x40, 0x48, 0xF5, 0xC3,
+      0xFA, 0x00, 0x00, 0x00, 0x00,
+      0xFA, 0x7F, 0xC0, 0x00, 0x00,
+      0xFA, 0x7F, 0x80, 0x00, 0x00,
+      0xA8,
+         0x18, 0x64,
+          0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x18, 0x65,
+          0xFB, 0x40, 0x09, 0x21, 0xFB, 0x4D, 0x12, 0xD8, 0x4A,
+         0x65, 0x65, 0x75, 0x6C, 0x65, 0x72,
+          0xFB, 0x40, 0x05, 0xBF, 0x0A, 0x8B, 0x14, 0x57, 0x69,
+         0x18, 0x69,
+          0xFB, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+         0x18, 0x66,
+          0xFA, 0x00, 0x00, 0x00, 0x00,
+         0x18, 0x67,
+          0xFA, 0x40, 0x49, 0x0F, 0xDA,
+         0x66, 0x65, 0x75, 0x6C, 0x65, 0x72, 0x32,
+          0xFA, 0x40, 0x2D, 0xF8, 0x54,
+         0x18, 0x6A,
+          0xFA, 0x00, 0x00, 0x00, 0x00};
 
-    // 6A                                   # text(10)
-    //    696E66696E6974697479              # "infinitity"
-    // F9 7C00                              # primitive(31744)
-    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "infinitity", INFINITY);
+int32_t GeneralFloatEncodeTests()
+{
+   UsefulBufC ExpectedFloats;
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+   UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloats));
+   ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
+   (void)spExpectedFloatsNoHalf; // Avoid unused variable error
+#else
+   UsefulBuf_MAKE_STACK_UB(OutBuffer, sizeof(spExpectedFloatsNoHalf));
+   ExpectedFloats = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloatsNoHalf);
+   (void)spExpectedFloats; // Avoid unused variable error
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
 
-    // 73                                   # text(19)
-    //    6E6567617469766520696E66696E6974697479 # "negative infinitity"
-    // F9 FC00                              # primitive(64512)
-    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative infinitity", -INFINITY);
+   QCBOREncodeContext EC;
+   QCBOREncode_Init(&EC, OutBuffer);
+   QCBOREncode_OpenArray(&EC);
 
-    // 63                                   # text(3)
-    //    4E614E                            # "NaN"
-    // F9 7E00                              # primitive(32256)
-    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "NaN", NAN);
+   QCBOREncode_AddDouble(&EC, 0.0);
+   QCBOREncode_AddDouble(&EC, 3.14);
+   QCBOREncode_AddDoubleNoPreferred(&EC, 0.0);
+   QCBOREncode_AddDoubleNoPreferred(&EC, NAN);
+   QCBOREncode_AddDoubleNoPreferred(&EC, INFINITY);
 
-    // TODO: test a few NaN variants
+   QCBOREncode_AddFloat(&EC, 0.0);
+   QCBOREncode_AddFloat(&EC, 3.14f);
+   QCBOREncode_AddFloatNoPreferred(&EC, 0.0f);
+   QCBOREncode_AddFloatNoPreferred(&EC, NAN);
+   QCBOREncode_AddFloatNoPreferred(&EC, INFINITY);
 
-    // 63                                   # text(3)
-    //    6F6E65                            # "one"
-    // F9 3C00                              # primitive(15360)
-    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one", 1.0);
+   QCBOREncode_OpenMap(&EC);
 
-    // 69                                   # text(9)
-    //    6F6E65207468697264                # "one third"
-    // F9 3555                              # primitive(13653)
-    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one third", 0.333251953125);
+   QCBOREncode_AddDoubleToMapN(&EC, 100, 0.0);
+   QCBOREncode_AddDoubleToMapN(&EC, 101, 3.1415926);
+   QCBOREncode_AddDoubleToMap(&EC, "euler", 2.71828182845904523536);
+   QCBOREncode_AddDoubleNoPreferredToMapN(&EC, 105, 0.0);
 
-    // 76                                   # text(22)
-    //   6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
-    // F9 7BFF                              # primitive(31743)
-    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision",65504.0);
+   QCBOREncode_AddFloatToMapN(&EC, 102, 0.0f);
+   QCBOREncode_AddFloatToMapN(&EC, 103, 3.1415926f);
+   QCBOREncode_AddFloatToMap(&EC, "euler2", 2.71828182845904523536f);
+   QCBOREncode_AddFloatNoPreferredToMapN(&EC, 106, 0.0f);
 
-    // 76                                   # text(22)
-    //   6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
-    // F9 7BFF                              # primitive(31743)
-    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision point one",65504.1);
+   QCBOREncode_CloseMap(&EC);
+   QCBOREncode_CloseArray(&EC);
 
-    // 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_AddDoubleAsSmallestToMap(&EC, "too-large half-precision", 65536.0);
+   UsefulBufC Encoded;
+   QCBORError uErr = QCBOREncode_Finish(&EC, &Encoded);
+   if(uErr) {
+      return -1;
+   }
 
-    // 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_AddDoubleAsSmallestToMap(&EC, "smallest subnormal", 0.0000000596046448);
+   if(UsefulBuf_Compare(Encoded, ExpectedFloats)) {
+      return -3;
+   }
 
-    // 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_AddDoubleAsSmallestToMap(&EC, "smallest normal",    0.0000610351526F);
+   return 0;
+}
 
-    // 71                                   # text(17)
-    //    62696767657374207375626E6F726D616C # "biggest subnormal"
-    // F9 0400                              # primitive(1024)
-    // in hex single is 0x38800000, exponent -14, significand 0
-    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest subnormal",  0.0000610351563F);
 
-    // 70                                   # text(16)
-    //    7375626E6F726D616C2073696E676C65  # "subnormal single"
-    // FB 37C16C2800000000                  # primitive(4017611261645684736)
-    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "subnormal single", 4e-40F);
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+/* returns 0 if equivalent, non-zero if not equivalent */
+static int CHECK_EXPECTED_DOUBLE(double val, double expected)
+{
+   double diff = val - expected;
 
-    // 03                                   # unsigned(3)
-    // F9 C000                              # primitive(49152)
-    QCBOREncode_AddDoubleAsSmallestToMapN(&EC, 3, -2.0);
+   diff = fabs(diff);
 
-    // 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_AddDoubleAsSmallestToMap(&EC, "large single exp", 2.5521177519070385E+38); // Exponent fits  single
+   if(diff > 0.000001) {
+      return 1;
+   } else {
+      return 0;
+   }
+}
+#endif
 
-    // 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_AddDoubleAsSmallestToMap(&EC, "too-large single exp", 5.104235503814077E+38);
 
-    // 66                                   # text(6)
-    //    646664666465                      # "dfdfde"
-    // FA 4B800000                          # primitive(1266679808)
-    // Single with no precision loss
-    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest single with prec", 16777216);
+int32_t GeneralFloatDecodeTests()
+{
+   UsefulBufC TestData = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedFloats);
 
-    // 78 18                                # text(24)
-    //    626967676573742073696E676C6520776974682070726563 # "biggest single with prec"
-    // FA 4B800000                          # primitive(1266679808)
-    // Double becuase of precision loss
-    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "first single with prec loss", 16777217);
+   QCBORDecodeContext DC;
+   QCBORDecode_Init(&DC, TestData, 0);
 
-    // Just a convenient marker when cutting and pasting encoded CBOR
-    QCBOREncode_AddSZStringToMapN(&EC, 1, "fin");
+   QCBORItem Item;
+   QCBORError uErr;
 
-    QCBOREncode_CloseMap(&EC);
+   QCBORDecode_GetNext(&DC, &Item);
+   if(Item.uDataType != QCBOR_TYPE_ARRAY) {
+      return -1;
+   }
 
-    UsefulBufC EncodedHalfs;
-    QCBORError nReturn = QCBOREncode_Finish(&EC, &EncodedHalfs);
-    if(nReturn != QCBOR_SUCCESS) {
-        return -1;
-    }
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      Item.val.dfnum != 0.0) {
+      return -2;
+   }
+#else
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_ERR_HALF_PRECISION_UNSUPPORTED) {
+      return -3;
+   }
+#endif
 
-    if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedSmallest))) {
-        return -3;
-    }
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      Item.val.dfnum != 3.14) {
+      return -4;
+   }
 
-    return 0;
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      Item.val.dfnum != 0.0) {
+      return -5;
+   }
+
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      !isnan(Item.val.dfnum)) {
+      return -6;
+   }
+
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      Item.val.dfnum != INFINITY) {
+      return -7;
+   }
+
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      Item.val.dfnum != 0.0) {
+      return -8;
+   }
+
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      CHECK_EXPECTED_DOUBLE(3.14, Item.val.dfnum)) {
+      return -9;
+   }
+
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      Item.val.dfnum != 0.0) {
+      return -10;
+   }
+
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      !isnan(Item.val.dfnum)) {
+      return -11;
+   }
+
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_DOUBLE ||
+      Item.val.dfnum != INFINITY) {
+      return -12;
+   }
+
+#else
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_ERR_HALF_PRECISION_UNSUPPORTED) {
+      return -13;
+   }
+
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_FLOAT ||
+      Item.val.fnum != 3.14f) {
+      return -14;
+   }
+
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_FLOAT ||
+      Item.val.fnum != 0.0f) {
+      return -15;
+   }
+
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_FLOAT ||
+      !isnan(Item.val.fnum)) {
+      return -16;
+   }
+
+   uErr = QCBORDecode_GetNext(&DC, &Item);
+   if(uErr != QCBOR_SUCCESS ||
+      Item.uDataType != QCBOR_TYPE_FLOAT ||
+      Item.val.fnum != INFINITY) {
+      return -17;
+   }
+#endif
+   /* Sufficent test coverage. Don't need to decode the rest */
+
+   return 0;
 }
 
 
@@ -491,6 +919,3 @@
     return 0;
 }
 #endif
-
-
-
diff --git a/test/float_tests.h b/test/float_tests.h
index f777156..54daa3f 100644
--- a/test/float_tests.h
+++ b/test/float_tests.h
@@ -15,11 +15,26 @@
 
 #include <stdint.h>
 
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
+
 int32_t HalfPrecisionDecodeBasicTests(void);
 
 int32_t DoubleAsSmallestTest(void);
 
 int32_t HalfPrecisionAgainstRFCCodeTest(void);
 
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
+
+/*
+ This calls each and every method for encoding
+ floating-point numbers.
+ */
+int32_t GeneralFloatEncodeTests(void);
+
+/*
+ Tests basic float decoding.
+ */
+int32_t GeneralFloatDecodeTests(void);
+
 
 #endif /* float_tests_h */
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index deb4c6c..c3dcc1e 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -372,7 +372,7 @@
       return  -1;
 
 
-   if((  nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
+   if((   nCBORError = QCBORDecode_GetNext(pDCtx, &Item)))
       return (int32_t)nCBORError;
    if(Item.uDataType != QCBOR_TYPE_INT64 ||
       Item.val.int64 != 4294967295)
@@ -1276,19 +1276,19 @@
       UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) {
       return -17;
    }
-   
-   
+
+
    /*
     Test with map that nearly QCBOR_MAX_ITEMS_IN_ARRAY items in a
     map that when interpreted as an array will be too many. Test
     data just has the start of the map, not all the items in the map.
     */
    static const uint8_t pTooLargeMap[] = {0xb9, 0xff, 0xfd};
-   
+
    QCBORDecode_Init(&DCtx,
                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pTooLargeMap),
                     QCBOR_DECODE_MODE_MAP_AS_ARRAY);
-   
+
    if((QCBOR_ERR_ARRAY_TOO_LONG != QCBORDecode_GetNext(&DCtx, &Item))) {
       return -50;
    }
@@ -2105,14 +2105,14 @@
    0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT
 
    // CBOR_TAG_B64
-   0xc1, 0xcf, 0xd8, 0x22, // 0xee, // Epoch date with extra tags TODO: fix this test
+   0xc1, 0xcf, 0xd8, 0x22, // 0xee, // Epoch date with extra tags
    0x1a, 0x53, 0x72, 0x4E, 0x01,
 
    0xc1, // tag for epoch date
    0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too large integer
 
    0xc1, // tag for epoch date
-   0xfa, 0x3f, 0x8c, 0xcc, 0xcd, // double with value 1.1
+   0xfa, 0x3f, 0x8c, 0xcc, 0xcd, // single with value 1.1
 
    0xc1, // tag for epoch date
    0xfa, 0x7f, 0x7f, 0xff, 0xff, // 3.4028234663852886e+38 too large
@@ -2127,7 +2127,7 @@
 
 
 // have to check float expected only to within an epsilon
-int CHECK_EXPECTED_DOUBLE(double val, double expected) {
+static int CHECK_EXPECTED_DOUBLE(double val, double expected) {
 
    double diff = val - expected;
 
@@ -2160,7 +2160,7 @@
       return -2;
    }
 
-   // Epoch date
+   // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT
    if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
       return -3;
    if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
@@ -2186,6 +2186,7 @@
    }
 
    // Epoch date in float format with fractional seconds
+#ifndef QCBOR_DISABLE_FLOAT_HW_USE
    if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item)))
       return -8;
    if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
@@ -2205,12 +2206,28 @@
    }
 
    // Largest double epoch date supported
-   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_SUCCESS ||
-      Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
-      Item.val.epochDate.nSeconds != 9223372036854773760 ||
-      Item.val.epochDate.nSeconds == 0) {
-      return -12;
+    if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_SUCCESS ||
+       Item.uDataType != QCBOR_TYPE_DATE_EPOCH ||
+       Item.val.epochDate.nSeconds != 9223372036854773760 ||
+       Item.val.epochDate.nSeconds == 0) {
+       return -12;
+    }
+#else
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_UNSUPPORTED) {
+      return -80;
    }
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_UNSUPPORTED) {
+      return -80;
+   }
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_UNSUPPORTED) {
+      return -80;
+   }
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_UNSUPPORTED) {
+      return -80;
+   }
+#endif
+
+
    // TODO: could use a few more tests with float, double, and half precsion
    // and negative (but coverage is still pretty good)
 
@@ -4096,8 +4113,10 @@
          [],
          []
       ]
-   }
+ }
  */
+
+
 static const uint8_t spMapOfEmpty[] = {
    0xa6, 0x00, 0x80, 0x09, 0x82, 0x80, 0x80, 0x08, 0xa3, 0x01,
    0x80, 0x02, 0xa0, 0x03, 0x80, 0x04, 0xa0, 0x05, 0x9f, 0xff,
@@ -4826,15 +4845,15 @@
    if(uCBORError != QCBOR_SUCCESS) {
       return 5;
    }
-   
-   
+
+
    // --- Sequence with unclosed indefinite length array ---
    static const uint8_t xx[] = {0x01, 0x9f, 0x02};
-   
+
    QCBORDecode_Init(&DCtx,
                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(xx),
                     QCBOR_DECODE_MODE_NORMAL);
-   
+
    // Get the first item
    uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
    if(uCBORError != QCBOR_SUCCESS) {
@@ -4843,7 +4862,7 @@
    if(Item.uDataType != QCBOR_TYPE_INT64) {
       return 8;
    }
-   
+
    // Get a second item
    uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
    if(uCBORError != QCBOR_SUCCESS) {
@@ -4860,14 +4879,14 @@
       return 11;
    }
 
-   
+
    // --- Sequence with a closed indefinite length array ---
    static const uint8_t yy[] = {0x01, 0x9f, 0xff};
-   
+
    QCBORDecode_Init(&DCtx,
                     UsefulBuf_FROM_BYTE_ARRAY_LITERAL(yy),
                     QCBOR_DECODE_MODE_NORMAL);
-   
+
    // Get the first item
    uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
    if(uCBORError != QCBOR_SUCCESS) {
@@ -4876,7 +4895,7 @@
    if(Item.uDataType != QCBOR_TYPE_INT64) {
       return 13;
    }
-   
+
    // Get a second item
    uCBORError = QCBORDecode_GetNext(&DCtx, &Item);
    if(uCBORError != QCBOR_SUCCESS) {
@@ -4893,7 +4912,7 @@
       return 16;
    }
 
-   
+
    return 0;
 }
 
diff --git a/test/run_tests.c b/test/run_tests.c
index 794c456..0adccd4 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -94,9 +94,13 @@
     TEST_ENTRY(IntegerValuesParseTest),
     TEST_ENTRY(MemPoolTest),
     TEST_ENTRY(IndefiniteLengthStringTest),
+#ifndef QCBOR_DISABLE_PREFERRED_FLOAT
     TEST_ENTRY(HalfPrecisionDecodeBasicTests),
     TEST_ENTRY(DoubleAsSmallestTest),
     TEST_ENTRY(HalfPrecisionAgainstRFCCodeTest),
+#endif /* QCBOR_DISABLE_PREFERRED_FLOAT */
+    TEST_ENTRY(GeneralFloatEncodeTests),
+    TEST_ENTRY(GeneralFloatDecodeTests),
     TEST_ENTRY(BstrWrapTest),
     TEST_ENTRY(BstrWrapErrorTest),
     TEST_ENTRY(BstrWrapNestTest),