more thorough removal of float
diff --git a/Makefile b/Makefile
index adb38ba..db16964 100644
--- a/Makefile
+++ b/Makefile
@@ -8,7 +8,7 @@
 #
 
 
-CFLAGS=-I inc -I test -Os -Wcast-align -Wall -Werror -pedantic-errors -Wextra -Wshadow -Wparentheses -Wconversion -xc -std=c99
+CFLAGS=-I inc -I test -Os -DQCBOR_CONFIG_DISABLE_ENCODE_IEEE754
 
 QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/ieee754.o
 
diff --git a/inc/qcbor.h b/inc/qcbor.h
index 40b08e8..4f0c068 100644
--- a/inc/qcbor.h
+++ b/inc/qcbor.h
@@ -614,6 +614,137 @@
  complex and mainly handled by QCBORDecode_GetNext(). Decoding of the
  structure of tagged data not built-in (if there is any) has to be
  implemented by the caller.
+ 
+ By default full IEEE 754 floating-point support is enabled including
+ preferred serialization of floating-point numbers as per section 4
+ of the CBOR RFC (TODO: fix this) . With preferred
+ serialization, the decoder 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 a zero, NaN and
+ infinity are frequently used. On the decode side, half-precision and single-precision
+ floats are always returned as doubles.
+ 
+ Preferred floating point serialization does NOT depend on
+ the CPU having floating-point HW or the compiler
+ bringing a (sometimes large) library to compensate for
+ lack of CPU support.
+ 
+ If preferred floating point serialization is disabled, then
+ floats and doubles may still be encoded, but they will
+ be encoded as their normal size and returned as a
+ float or double during decoding. There is no way to
+ encode half-precision and when
+ a half-precision data item is encountered during decoding, an
+ error will be returned.
+ 
+  QCBOR can always encode and decode floats and doubles
+ even if the CPU HW doesn't support them, even if
+ preferred serialization is disabled and doesn't need SW-based
+ floating-point to be brought in by the compiler.
+ 
+ TODO: should there be a runtime option to disable preferred float serialization as some protocols will not want half-precision support.  Maybe a mode? Maybe an API?
+ TODO: a way to explicitly encode half-precision?
+ 
+ In order to process floating-point epoch dates, QCBOR needs
+ floating point arithmetic. On CPUs that have no floating-point
+ hardware, QCBOR may be set up to not using floating-point
+ aritthmetic, in which case floating-point epoch date values
+ will be considered and error when encoding. QCBOR never
+ generates floating-point values when encoding dates.
+ 
+
+ 
+ 
+ . For environments with
+ no floating point HW, or to save some object code , some floating
+ point features may be disabled. In this limited mode  float and double values may still be encoded
+ and decoded, but there will be no preferred encoding of them.
+When decoding half-precison values and floating-point format
+ dates will be treated as an error. In this limited mode no
+ floating point operations like conversion in size or to integers
+  are used so in environments with no floating point HW, the
+ compiler will not have to add in support with SW.
+ 
+ -----
+  Default full float support
+ 
+   Disable: preferred float encoding / decoding. Savs 300 bytes during
+ decoding and 300 bytes during encodeing. Can still encode / decode
+  float and double values.  This need not be disabled on devices
+ with no floating point HW because preferred encoding / decoding
+ is all done internally with shifts and masks.
+ 
+  QCBOR_DISABLE_FLOAT_HW_USE. Disable use of floating point HW. Saves a very small amount of
+ code on devices with no floating point HW and a lot of code on
+ devices without floating point HW. The compiler won't bring in
+  the floating point SW that emulates the HW. When this is done
+   floating point dates are not supported. When this is disabled,
+ the following is not available: handling of floating-point epoch dates.
+ 
+ 
+ QCBOR_DISABLE_FLOAT_PREFERRED_SERIALIZATION.  This disables
+ preferred serialization of floating-point values. It also
+ disables all support for half-precision floating-point. The main
+ reason to disable this is to reduce object code in the decoder
+  by a few hundred bytes. It is not as necessary to
+ disable this to reduce size of the encoder, because avoiding
+ calls to the floating-point encode functions has the same effect.
+ 
+ Even when this is disabled, QCBOR
+ can encode and decode float and double values. What is
+ unavailable is the reduction in size of encoded floats and
+ the ability to decode half-precision.
+ 
+ Preferred serialization encoding and decoding
+ does not use floating-point HW, so it is not necessary to
+ disable this on CPUs without floating-point support.  However,
+ if a CPU doesn't support floating point, then use of floating
+ point is usually very expensive and slow because the compiler
+ must bring in large SW libraries. For that reason some may
+ choose to disable floating-point preferred serialization because it is
+ unlikely to be needed.
+ 
+ QCBOR_DISABLE_FLOAT_HW_USE. This disables
+ all use of CPU floating-point HW and the
+ often large and slow SW libraries the compiler substitutes if
+ there is no floating-point HW.
+ The only effect on QCBOR features
+ is that floating-point epoch date formats will result in a decoding error. Disabling
+ this reduces QCBOR in size by very little, but reduces
+ the overall executable size a lot on CPUs with no floating-point
+ HW by avoiding the compiler-supplied SW libraries. Since
+ floaing-point dates are not a very necessary feature, it
+ is advisable to define this on CPUs with no floating-point HW.
+
+ 
+ 
+ If you are running on a CPU with no floating point HW and you
+ don't need floating point date support, definitely disable XXX. If
+ you don't the compiler is likely to bring in large SW libraries
+ to provide the functions the HW does not.
+ 
+ If you want to save object ocde by disabling preferred encoding
+ of floats turn off QCBOR_DISABLE_PREFERRED_FLOAT. Note that this doesn't use floating point
+ HW so it is OK to leave enabled on CPUs with no floating
+ point support if you don't mind the extra 300 bytes of object
+ code on the decode side. On the encode side the floating
+ point code will be dead-stripped if not used.
+ 
+ Float features
+  - preferred encoding, encode side
+ - preferred encoding, decode side
+ - floating-point dates
+ 
+ 
+ Two modes?
+ 
+ disable use of preferred encoding / decoding and half precision support? This still
+ needs no floating point HW or SW.
+ 
+ 
+ -----
 
  Summary Limits of this implementation:
  - The entire encoded CBOR must fit into contiguous memory.
@@ -792,7 +923,11 @@
     should be treated as such. The strange situation is a CPU with a very
     small size_t (e.g., a 16-bit CPU) and a large string (e.g., > 65KB).
     */
-    QCBOR_ERR_STRING_TOO_LONG = 24
+    QCBOR_ERR_STRING_TOO_LONG = 24,
+   
+   /** Decoding of floating-point epoch dates is unsupported and a
+    floating-point date was encountered by the decoder. */
+   QCBOR_ERR_FLOAT_DATE_UNSUPPORTED = 25,
 
 } QCBORError;
 
@@ -947,6 +1082,8 @@
           It is @c UINT16_MAX when decoding indefinite-lengths maps
           and arrays. */
       uint16_t    uCount;
+      /** The value for @c uDataType @ref QCBOR_TYPE_FLOAT. */
+      double      fnum;
       /** The value for @c uDataType @ref QCBOR_TYPE_DOUBLE. */
       double      dfnum;
       /** The value for @c uDataType @ref QCBOR_TYPE_DATE_EPOCH. */
diff --git a/src/ieee754.c b/src/ieee754.c
index 41f60cf..ac454b4 100644
--- a/src/ieee754.c
+++ b/src/ieee754.c
@@ -10,6 +10,8 @@
  Created on 7/23/18
  =============================================================================*/
 
+#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
+
 #include "ieee754.h"
 #include <string.h> // For memcpy()
 
@@ -391,8 +393,8 @@
 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.
+    // 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;
@@ -451,6 +453,74 @@
 
 
 // Public function; see ieee754.h
+double IEEE754_FloatToDouble(float f)
+{
+    const uint32_t uFloat = CopyFloatToUint32(f);
+    // 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;
@@ -526,3 +596,4 @@
     return result;
 }
 
+#endif /* QCBOR_CONFIG_DISABLE_ENCODE_IEEE754 */
diff --git a/src/ieee754.h b/src/ieee754.h
index 705ef62..47bfea5 100644
--- a/src/ieee754.h
+++ b/src/ieee754.h
@@ -10,6 +10,8 @@
  Created on 7/23/18
  =============================================================================*/
 
+#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
+
 #ifndef ieee754_h
 #define ieee754_h
 
@@ -96,6 +98,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(float f);
+
 
 // Both tags the value and gives the size
 #define IEEE754_UNION_IS_HALF   2
@@ -146,7 +155,7 @@
 #endif /* ieee754_h */
 
 
-
+#endif /* QCBOR_CONFIG_DISABLE_ENCODE_IEEE754 */
 
 
 
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 1b6ff3e..532da1e 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -608,12 +608,24 @@
       // caught before this is called.
 
       case HALF_PREC_FLOAT:
+#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
+         // The caast 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_UNSUPPORTED;
+#endif
          break;
       case SINGLE_PREC_FLOAT:
-         pDecodedItem->val.dfnum = (double)UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
-         pDecodedItem->uDataType = QCBOR_TYPE_DOUBLE;
+#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
+         // The caast to uint32_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_FloatToDouble((uint32_t)uNumber);
+#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);
@@ -1221,7 +1233,10 @@
          pDecodedItem->val.epochDate.nSeconds = (int64_t)pDecodedItem->val.uint64;
          break;
 
+         // TODO: test this with float and half input
       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
@@ -1231,7 +1246,7 @@
          // 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
+         // 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.
          //
@@ -1242,7 +1257,8 @@
          //
          // 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.
+         // where this this code would go wrong and some compilers
+         // will generate warnings or errors.
          const double d = pDecodedItem->val.dfnum;
          if(d > (double)(INT64_MAX - 0x7ff)) {
             nReturn = QCBOR_ERR_DATE_OVERFLOW;
@@ -1251,8 +1267,18 @@
          pDecodedItem->val.epochDate.nSeconds = (int64_t)d;
          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 5cc0bd7..5536194 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -616,9 +616,29 @@
  */
 void QCBOREncode_AddDouble(QCBOREncodeContext *me, double dNum)
 {
+#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
    const IEEE754_union uNum = IEEE754_DoubleToSmallest(dNum);
-
+   
    QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
+#else
+   QCBOREncode_AddType7(me, sizeof(uint64_t), UsefulBufUtil_CopyDoubleToUint64(dNum));
+#endif
+
+}
+
+
+/*
+ Public functions for closing arrays and maps. See qcbor.h
+ */
+void QCBOREncode_AddFloat(QCBOREncodeContext *me, float fNum)
+{
+#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
+   const IEEE754_union uNum = IEEE754_FloatToSmallest(fNum);
+   
+   QCBOREncode_AddType7(me, uNum.uSize, uNum.uValue);
+#else
+   QCBOREncode_AddType7(me, sizeof(uint32_t), UsefulBufUtil_CopyFloatToUint32(fNum));
+#endif
 }
 
 
diff --git a/test/float_tests.c b/test/float_tests.c
index 20057c3..54683c3 100644
--- a/test/float_tests.c
+++ b/test/float_tests.c
@@ -10,6 +10,8 @@
  Created on 9/19/18
  =============================================================================*/
 
+#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
+
 #include "float_tests.h"
 #include "qcbor.h"
 #include "half_to_double_from_rfc7049.h"
@@ -491,5 +493,6 @@
 }
 #endif
 
+#endif /* QCBOR_CONFIG_DISABLE_ENCODE_IEEE754 */
 
 
diff --git a/test/float_tests.h b/test/float_tests.h
index f777156..50f3e8a 100644
--- a/test/float_tests.h
+++ b/test/float_tests.h
@@ -15,11 +15,15 @@
 
 #include <stdint.h>
 
+#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
+
 int32_t HalfPrecisionDecodeBasicTests(void);
 
 int32_t DoubleAsSmallestTest(void);
 
 int32_t HalfPrecisionAgainstRFCCodeTest(void);
 
+#endif /* QCBOR_CONFIG_DISABLE_ENCODE_IEEE754 */
+
 
 #endif /* float_tests_h */
diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c
index a9e1fb2..140283f 100644
--- a/test/qcbor_decode_tests.c
+++ b/test/qcbor_decode_tests.c
@@ -2125,6 +2125,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 ||
@@ -2132,6 +2133,10 @@
       CHECK_EXPECTED_DOUBLE(Item.val.epochDate.fSecondsFraction, 0.1 )) {
       return -9;
    }
+#else
+   if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_FLOAT_DATE_UNSUPPORTED)
+      return -80;
+#endif
 
    // Epoch date float that is too large for our representation
    if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) {
diff --git a/test/run_tests.c b/test/run_tests.c
index 8e52dae..78450eb 100644
--- a/test/run_tests.c
+++ b/test/run_tests.c
@@ -91,9 +91,11 @@
     TEST_ENTRY(IntegerValuesParseTest),
     TEST_ENTRY(MemPoolTest),
     TEST_ENTRY(IndefiniteLengthStringTest),
+#ifndef QCBOR_CONFIG_DISABLE_ENCODE_IEEE754
     TEST_ENTRY(HalfPrecisionDecodeBasicTests),
     TEST_ENTRY(DoubleAsSmallestTest),
     TEST_ENTRY(HalfPrecisionAgainstRFCCodeTest),
+#endif /* QCBOR_CONFIG_DISABLE_ENCODE_IEEE754 */
     TEST_ENTRY(BstrWrapTest),
     TEST_ENTRY(BstrWrapErrorTest),
     TEST_ENTRY(BstrWrapNestTest),