Merge floating point support in; new test runner
diff --git a/Makefile b/Makefile
index def1d4e..233164b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,18 +1,27 @@
 CFLAGS=-I inc -I test -Os
 
-QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o 
-TEST_OBJ=test/basic_test.o test/bstrwrap_tests.o
+QCBOR_OBJ=src/UsefulBuf.o src/qcbor_encode.o src/qcbor_decode.o src/ieee754.o
+
+TEST_OBJ=test/basic_test.o test/bstrwrap_tests.o test/run_tests.o test/half_precision_test.o \
+  test/half_to_double_from_rfc7049.o
+
 CMD_LINE_OBJ=$(QCBOR_OBJ) $(TEST_OBJ) cmd_line_main.o
 
 qcbortest: $(CMD_LINE_OBJ)
 	cc -o $@ $^ $(CFLAGS)
 
 src/UsefulBuf.o:	inc/UsefulBuf.h
-src/qcbor_decode.o:	inc/UsefulBuf.h inc/qcbor.h
-src/qcbor_encode.o:	inc/UsefulBuf.h inc/qcbor.h
+src/qcbor_decode.o:	inc/UsefulBuf.h inc/qcbor.h src/ieee754.h
+src/qcbor_encode.o:	inc/UsefulBuf.h inc/qcbor.h src/ieee754.h
+src/iee754.o:	src/ieee754.h 
+
 test/basic_test.o:	test/basic_test.h inc/qcbor.h inc/UsefulBuf.h
 test/bstrwrap_tests.o:	test/bstrwrap_tests.h inc/qcbor.h inc/UsefulBuf.h
-cmd_line_main.o:	test/basic_test.h test/bstrwrap_tests.h
+test/run_tests.o:	test/half_precision_test.h test/run_tests.h test/basic_test.h test/bstrwrap_tests.h
+test/half_precision_test.o:	inc/qcbor.h test/half_precision_test.h test/half_to_double_from_rfc7049.h
+test/half_to_double_from_rfc7049.o:	test/half_to_double_from_rfc7049.h
+
+cmd_line_main.o:	test/run_tests.h
 
 clean:
 	rm $(CMD_LINE_OBJ)
diff --git a/QCBOR.xcodeproj/project.pbxproj b/QCBOR.xcodeproj/project.pbxproj
index 89e53fe..c6a348b 100644
--- a/QCBOR.xcodeproj/project.pbxproj
+++ b/QCBOR.xcodeproj/project.pbxproj
@@ -8,6 +8,10 @@
 
 /* Begin PBXBuildFile section */
 		E73B5756216071900080D658 /* bstrwrap_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B5755216071900080D658 /* bstrwrap_tests.c */; };
+		E73B57592161CA690080D658 /* ieee754.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B57582161CA690080D658 /* ieee754.c */; };
+		E73B575E2161CA7C0080D658 /* half_precision_test.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B575A2161CA7C0080D658 /* half_precision_test.c */; };
+		E73B575F2161CA7C0080D658 /* half_to_double_from_rfc7049.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B575D2161CA7C0080D658 /* half_to_double_from_rfc7049.c */; };
+		E73B57652161F8F80080D658 /* run_tests.c in Sources */ = {isa = PBXBuildFile; fileRef = E73B57632161F8F70080D658 /* run_tests.c */; };
 		E776E08F214AE07500E67947 /* qcbor_encode.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E08C214AE07400E67947 /* qcbor_encode.c */; };
 		E776E090214AE07500E67947 /* UsefulBuf.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E08D214AE07500E67947 /* UsefulBuf.c */; };
 		E776E091214AE07500E67947 /* qcbor_decode.c in Sources */ = {isa = PBXBuildFile; fileRef = E776E08E214AE07500E67947 /* qcbor_decode.c */; };
@@ -30,6 +34,14 @@
 /* Begin PBXFileReference section */
 		E73B5754216071900080D658 /* bstrwrap_tests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = bstrwrap_tests.h; path = test/bstrwrap_tests.h; sourceTree = "<group>"; };
 		E73B5755216071900080D658 /* bstrwrap_tests.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = bstrwrap_tests.c; path = test/bstrwrap_tests.c; sourceTree = "<group>"; };
+		E73B57572161CA680080D658 /* ieee754.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ieee754.h; path = src/ieee754.h; sourceTree = "<group>"; };
+		E73B57582161CA690080D658 /* ieee754.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = ieee754.c; path = src/ieee754.c; sourceTree = "<group>"; };
+		E73B575A2161CA7C0080D658 /* half_precision_test.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = half_precision_test.c; path = test/half_precision_test.c; sourceTree = "<group>"; };
+		E73B575B2161CA7C0080D658 /* half_to_double_from_rfc7049.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = half_to_double_from_rfc7049.h; path = test/half_to_double_from_rfc7049.h; sourceTree = "<group>"; };
+		E73B575C2161CA7C0080D658 /* half_precision_test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = half_precision_test.h; path = test/half_precision_test.h; sourceTree = "<group>"; };
+		E73B575D2161CA7C0080D658 /* half_to_double_from_rfc7049.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = half_to_double_from_rfc7049.c; path = test/half_to_double_from_rfc7049.c; sourceTree = "<group>"; };
+		E73B57632161F8F70080D658 /* run_tests.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = run_tests.c; path = test/run_tests.c; sourceTree = "<group>"; };
+		E73B57642161F8F80080D658 /* run_tests.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = run_tests.h; path = test/run_tests.h; sourceTree = "<group>"; };
 		E776E07C214ADF7F00E67947 /* QCBOR */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = QCBOR; sourceTree = BUILT_PRODUCTS_DIR; };
 		E776E08C214AE07400E67947 /* qcbor_encode.c */ = {isa = PBXFileReference; fileEncoding = 4; indentWidth = 3; lastKnownFileType = sourcecode.c.c; name = qcbor_encode.c; path = src/qcbor_encode.c; sourceTree = "<group>"; tabWidth = 3; };
 		E776E08D214AE07500E67947 /* UsefulBuf.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = UsefulBuf.c; path = src/UsefulBuf.c; sourceTree = "<group>"; };
@@ -76,6 +88,8 @@
 		E776E08B214AE06600E67947 /* src */ = {
 			isa = PBXGroup;
 			children = (
+				E73B57582161CA690080D658 /* ieee754.c */,
+				E73B57572161CA680080D658 /* ieee754.h */,
 				E776E08E214AE07500E67947 /* qcbor_decode.c */,
 				E776E08C214AE07400E67947 /* qcbor_encode.c */,
 				E776E08D214AE07500E67947 /* UsefulBuf.c */,
@@ -95,6 +109,12 @@
 		E776E095214AE0B600E67947 /* test */ = {
 			isa = PBXGroup;
 			children = (
+				E73B57632161F8F70080D658 /* run_tests.c */,
+				E73B57642161F8F80080D658 /* run_tests.h */,
+				E73B575A2161CA7C0080D658 /* half_precision_test.c */,
+				E73B575C2161CA7C0080D658 /* half_precision_test.h */,
+				E73B575D2161CA7C0080D658 /* half_to_double_from_rfc7049.c */,
+				E73B575B2161CA7C0080D658 /* half_to_double_from_rfc7049.h */,
 				E776E09C214AEEEA00E67947 /* basic_test.c */,
 				E73B5754216071900080D658 /* bstrwrap_tests.h */,
 				E73B5755216071900080D658 /* bstrwrap_tests.c */,
@@ -160,7 +180,11 @@
 			buildActionMask = 2147483647;
 			files = (
 				E776E08F214AE07500E67947 /* qcbor_encode.c in Sources */,
+				E73B57592161CA690080D658 /* ieee754.c in Sources */,
+				E73B575F2161CA7C0080D658 /* half_to_double_from_rfc7049.c in Sources */,
+				E73B57652161F8F80080D658 /* run_tests.c in Sources */,
 				E776E091214AE07500E67947 /* qcbor_decode.c in Sources */,
+				E73B575E2161CA7C0080D658 /* half_precision_test.c in Sources */,
 				E776E090214AE07500E67947 /* UsefulBuf.c in Sources */,
 				E776E097214AE0C700E67947 /* cmd_line_main.c in Sources */,
 				E73B5756216071900080D658 /* bstrwrap_tests.c in Sources */,
diff --git a/README.md b/README.md
index 9d99438..39c4576 100644
--- a/README.md
+++ b/README.md
@@ -26,7 +26,6 @@
 This code in Laurence's GitHub has diverged some from the CAF source with some small simplifications and tidying up.  The full test suite is not up and running and available in GitHub yet, so some caution is advised. This should be remedies soon.
 
 The following modifications are planned:
-* Floating point support
 * Indefinite length support
 * Improve design for handling multiple tags
 
@@ -35,17 +34,25 @@
 ## Building
 There is a simple makefile for the UNIX style command line binary that compiles everything to run the tests.
 
-The actual non-test source files are these five:
+The actual non-test source files are these seven:
 * inc/UsefulBuf.h
 * inc/qcbor.h
 * src/UsefulBuf.c
 * src/qcbor_encode.c
 * src/qcbor_decode.c
+* src/ieee754.h
+* src/ieee754.c
 
 For most use cases you should just be able to add them to your project. Hopefully the easy portability of this implementation makes this work straight away, whatever your development environment is.
 
-The test directory includes some 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.
+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 always linked, however it 
+doesn't add very much to the size.
+
+The test directory includes some 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 run_tests() to invole them all. 
 
 
 
diff --git a/cmd_line_main.c b/cmd_line_main.c
index 87d0ecd..63c670c 100644
--- a/cmd_line_main.c
+++ b/cmd_line_main.c
@@ -25,24 +25,22 @@
  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  SOFTWARE.
  */
+//  Created by Laurence Lundblade on 9/13/18.
 
 #include <stdio.h>
 
-#include "basic_test.h"
-#include "bstrwrap_tests.h"
+#include "run_tests.h"
 
-int main(int argc, const char * argv[]) {
 
-    printf("basic-test_one Result %d\n", basic_test_one());
+int fputs_wrapper(const char *szString, void *ctx)
+{
+    return fputs(szString, (FILE *)ctx);
+}
 
-    printf("cose_sign1_tbs_test %d\n", cose_sign1_tbs_test());
 
-    printf("bstr_wrap_nest_test %d\n", bstr_wrap_nest_test());
-    
-    printf("bstr_wrap_error_test %d\n", bstr_wrap_error_test());
-    
-    printf("bstrwraptest %d\n", bstrwraptest());
-    
-    
-    return 0;
+int main(int argc, const char * argv[]) {   
+   
+    int nNumTestsFailed = run_tests(&fputs_wrapper, stdout, NULL);
+
+    return nNumTestsFailed;
 }
diff --git a/inc/UsefulBuf.h b/inc/UsefulBuf.h
index 9272b85..39c518f 100644
--- a/inc/UsefulBuf.h
+++ b/inc/UsefulBuf.h
@@ -509,6 +509,43 @@
 
 
 
+/*
+ Convenient functions to avoid type punning, compiler warnings and such
+ The optimizer reduces them to a simple assignment
+ This is a crusty corner of C. It shouldn't be this hard.
+ */
+static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f)
+{
+    uint32_t u32;
+    memcpy(&u32, &f, sizeof(uint32_t));
+    return u32;
+}
+
+static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d)
+{
+    uint64_t u64;
+    memcpy(&u64, &d, sizeof(uint64_t));
+    return u64;
+}
+
+static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64)
+{
+    double d;
+    memcpy(&d, &u64, sizeof(uint64_t));
+    return d;
+}
+
+static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32)
+{
+    float f;
+    memcpy(&f, &u32, sizeof(uint32_t));
+    return f;
+}
+
+
+
+
+
 /**
  UsefulOutBuf is a structure and functions (an object) that are good
  for serializing data into a buffer such as is often done with network
diff --git a/inc/qcbor.h b/inc/qcbor.h
index 58b9595..eec84c1 100644
--- a/inc/qcbor.h
+++ b/inc/qcbor.h
@@ -857,6 +857,122 @@
 #define QCBOREncode_AddDoubleToMapN(pCtx, nLabel, dNum) \
       QCBOREncode_AddDouble_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE, (dNum))
 
+/*
+ @brief  Add a half-precision floating point number to the encoded output
+ 
+ @param[in] pCtx      The encoding context to add the float to.
+ @param[in] szLabel   The string map label for this integer value.
+ @param[in] nLabel    The integer map label for this integer value.
+ @param[in] uTag      A CBOR type 6 tag
+ @param[in] fNum      The float to add.
+ 
+ This will truncate the precision of the single precision float to half-precision.
+ Numbers whose absolute value is larger than 65504 will be encoded as infinity as this is the largest number
+ half-precision can encode. Numbers whose absolute value is less than 5.96E−8 will be
+ encoded as 0. Single precision floats smaller than 6.10E−5 will be converted
+ half-precision subnormal numbers.
+ 
+ Infinity and NaN are handled correctly. NaN payloads are partially carried.
+ 
+ Half-precision floating point number take up 2 bytes, half that of single-precision.
+ 
+ This works the same as QCBOREncode_AddInt64_3() except it is for half-precision floats.
+
+ */
+
+void QCBOREncode_AddFloatAsHalf_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, float fNum);
+
+#define QCBOREncode_AddFloatAsHalf(pCtx, fNum) \
+      QCBOREncode_AddFloatAsHalf_3((pCtx), NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (fNum))
+
+#define QCBOREncode_AddFloatAsHalfToMap(pCtx, szLabel, fNum) \
+      QCBOREncode_AddFloatAsHalf_3((pCtx), (szLabel), QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (fNum))
+
+#define QCBOREncode_AddFloatAsHalfToMapN(pCtx, nLabel, fNum) \
+      QCBOREncode_AddFloatAsHalf_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE, (fNum))
+
+
+/*
+ @brief  Add a dynamically sized floating point number to the encoded output
+ 
+ @param[in] pCtx      The encoding context to add the float to.
+ @param[in] szLabel   The string map label for this integer value.
+ @param[in] nLabel    The integer map label for this integer value.
+ @param[in] uTag      A CBOR type 6 tag
+ @param[in] fNum      The float to add.
+ 
+ This will selectively encode the single-precision floating point number as either
+ 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 performed, otherwise it will not be performed.
+ 
+ This reduces the size of encoded messages a lot, maybe even half if most values are
+ 0, infinity or NaN.
+ 
+ Half-precision floating point numbers take up 2 bytes, half that of single-precision.
+ 
+ These will always be decoded into a float as standard C doesn't have a widely used
+ standard representation for half-precision floats yet.
+ 
+ This works the same as QCBOREncode_AddInt64_3() except it is for single and half-precision floats.
+ 
+ */
+
+void QCBOREncode_AddFloatAsSmallest_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, float fNum);
+
+#define QCBOREncode_AddFloatAsSmallest(pCtx, fNum) \
+      QCBOREncode_AddFloatAsSmallest_3((pCtx), NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (fNum))
+
+#define QCBOREncode_AddFloatAsSmallestToMap(pCtx, szLabel, fNum) \
+      QCBOREncode_AddFloatAsSmallest_3((pCtx), (szLabel), QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (fNum))
+
+#define QCBOREncode_AddFloatAsSmallestToMapN(pCtx, nLabel, fNum) \
+      QCBOREncode_AddFloatAsSmallest_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE, (fNum))
+
+
+/*
+ @brief  Add a dynamically sized floating point number to the encoded output
+ 
+ @param[in] pCtx      The encoding context to add the float to.
+ @param[in] szLabel   The string map label for this integer value.
+ @param[in] nLabel    The integer map label for this integer value.
+ @param[in] uTag      A CBOR type 6 tag
+ @param[in] dNum      The float to add.
+ 
+ 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 sent as a double.
+ 
+ Half-precision floating point numbers take up 2 bytes, half that of single-precision,
+ one quarter of double-preceision
+ 
+ This reduces the size of encoded messages a lot, maybe even by four if a most of values are
+ 0, infinity or NaN.
+ 
+ On decode, these will always be represented has float or double. Half-precision values
+ will decode as float as standard C doesn't have a widely used
+ standard representation for half-precision floats yet. The designer of the protocol
+ using this approach can / should assume that floats received actually have the precision
+ of double. They should probably cast the float received to double.
+ 
+ This works the same as QCBOREncode_AddInt64_3() except it is for floating point types.
+ 
+ */
+
+void QCBOREncode_AddDoubleAsSmallest_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, double dNum);
+
+#define QCBOREncode_AddDoubleAsSmallest(pCtx, dNum) \
+      QCBOREncode_AddDoubleAsSmallest_3((pCtx), NULL, QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (dNum))
+
+#define QCBOREncode_AddDoubleAsSmallestToMap(pCtx, szLabel, dNum) \
+      QCBOREncode_AddDoubleAsSmallest_3((pCtx), (szLabel), QCBOR_NO_INT_LABEL, CBOR_TAG_NONE, (dNum))
+
+#define QCBOREncode_AddDoubleAsSmallestToMapN(pCtx, nLabel, dNum) \
+      QCBOREncode_AddDoubleAsSmallest_3((pCtx), NULL, (nLabel), CBOR_TAG_NONE, (dNum))
+
 
 
 /**
diff --git a/run_tests.c b/run_tests.c
new file mode 100644
index 0000000..fe067b6
--- /dev/null
+++ b/run_tests.c
@@ -0,0 +1,9 @@
+//
+//  run_tests.c
+//  QCBOR
+//
+//  Created by Laurence Lundblade on 9/30/18.
+//  Copyright © 2018 Laurence Lundblade. All rights reserved.
+//
+
+#include "run_tests.h"
diff --git a/run_tests.h b/run_tests.h
new file mode 100644
index 0000000..2f8eea4
--- /dev/null
+++ b/run_tests.h
@@ -0,0 +1,14 @@
+//
+//  run_tests.h
+//  QCBOR
+//
+//  Created by Laurence Lundblade on 9/30/18.
+//  Copyright © 2018 Laurence Lundblade. All rights reserved.
+//
+
+#ifndef run_tests_h
+#define run_tests_h
+
+#include <stdio.h>
+
+#endif /* run_tests_h */
diff --git a/src/ieee754.c b/src/ieee754.c
new file mode 100644
index 0000000..7844c1a
--- /dev/null
+++ b/src/ieee754.c
@@ -0,0 +1,464 @@
+/*==============================================================================
+ Copyright 2018 Laurence Lundblade
+ 
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ 
+ (This is the MIT license)
+ ==============================================================================*/
+
+//
+//  ieee754.c
+//  Indefinite
+//
+//  Created by Laurence Lundblade on 7/23/18.
+//  Copyright © 2018 Laurence Lundblade. All rights reserved.
+//
+
+#include "ieee754.h"
+#include <string.h> // For memcpy()
+
+
+/*
+ This code is written for clarity and verifiability, not for size, on the assumption
+ that the optimizer will do a good job. The LLVM optimizer, -Os, does seem to do the
+ job and the resulting object code is smaller from combining code for the many different
+ cases (normal, subnormal, infinity, zero...) for the conversions.
+ 
+ Dead stripping is also really helpful to get code size down.
+ 
+ This code also works solely using shifts and masks and thus has no dependency on
+ any math libraries. It will even work if the CPU doesn't have any floating
+ point support.
+ 
+ The memcpy() dependency is only for CopyFloatToUint32() and friends which only
+ is needed to avoid type punning when converting the actual float bits to
+ an unsigned value so the bit shifts and masks can work.
+ */
+
+/*
+ The references used to write this code:
+ 
+ - IEEE 754-2008, particularly section 3.6 and 6.2.1
+ 
+ - https://en.wikipedia.org/wiki/IEEE_754 and subordinate pages
+ 
+ - https://stackoverflow.com/questions/19800415/why-does-ieee-754-reserve-so-many-nan-values
+ */
+
+
+// ----- Half Precsion -----------
+#define HALF_NUM_SIGNIFICAND_BITS (10)
+#define HALF_NUM_EXPONENT_BITS    (5)
+#define HALF_NUM_SIGN_BITS        (1)
+
+#define HALF_SIGNIFICAND_SHIFT    (0)
+#define HALF_EXPONENT_SHIFT       (HALF_NUM_SIGNIFICAND_BITS)
+#define HALF_SIGN_SHIFT           (HALF_NUM_SIGNIFICAND_BITS + HALF_NUM_EXPONENT_BITS)
+
+#define HALF_SIGNIFICAND_MASK     (0x3ff) // The lower 10 bits  // 0x03ff
+#define HALF_EXPONENT_MASK        (0x1f << HALF_EXPONENT_SHIFT) // 0x7c00 5 bits of exponent
+#define HALF_SIGN_MASK            (0x01 << HALF_SIGN_SHIFT) //  // 0x80001 bit of sign
+#define HALF_QUIET_NAN_BIT        (0x01 << (HALF_NUM_SIGNIFICAND_BITS-1)) // 0x0200
+
+/* Biased    Biased    Unbiased   Use
+    0x00       0        -15       0 and subnormal
+    0x01       1        -14       Smallest normal exponent
+    0x1e      30         15       Largest normal exponent
+    0x1F      31         16       NaN and Infinity  */
+#define HALF_EXPONENT_BIAS        (15)
+#define HALF_EXPONENT_MAX         (HALF_EXPONENT_BIAS)    //  15 Unbiased
+#define HALF_EXPONENT_MIN         (-HALF_EXPONENT_BIAS+1) // -14 Unbiased
+#define HALF_EXPONENT_ZERO        (-HALF_EXPONENT_BIAS)   // -15 Unbiased
+#define HALF_EXPONENT_INF_OR_NAN  (HALF_EXPONENT_BIAS+1)  //  16 Unbiased
+
+
+// ------ Single Precision --------
+#define SINGLE_NUM_SIGNIFICAND_BITS (23)
+#define SINGLE_NUM_EXPONENT_BITS    (8)
+#define SINGLE_NUM_SIGN_BITS        (1)
+
+#define SINGLE_SIGNIFICAND_SHIFT    (0)
+#define SINGLE_EXPONENT_SHIFT       (SINGLE_NUM_SIGNIFICAND_BITS)
+#define SINGLE_SIGN_SHIFT           (SINGLE_NUM_SIGNIFICAND_BITS + SINGLE_NUM_EXPONENT_BITS)
+
+#define SINGLE_SIGNIFICAND_MASK     (0x7fffffUL) // The lower 23 bits
+#define SINGLE_EXPONENT_MASK        (0xffUL << SINGLE_EXPONENT_SHIFT) // 8 bits of exponent
+#define SINGLE_SIGN_MASK            (0x01UL << SINGLE_SIGN_SHIFT) // 1 bit of sign
+#define SINGLE_QUIET_NAN_BIT        (0x01UL << (SINGLE_NUM_SIGNIFICAND_BITS-1))
+
+/* Biased  Biased   Unbiased  Use
+    0x0000     0     -127      0 and subnormal
+    0x0001     1     -126      Smallest normal exponent
+    0x7f     127        0      1
+    0xfe     254      127      Largest normal exponent
+    0xff     255      128      NaN and Infinity  */
+#define SINGLE_EXPONENT_BIAS        (127)
+#define SINGLE_EXPONENT_MAX         (SINGLE_EXPONENT_BIAS)    // 127  unbiased
+#define SINGLE_EXPONENT_MIN         (-SINGLE_EXPONENT_BIAS+1) // -126 unbiased
+#define SINGLE_EXPONENT_ZERO        (-SINGLE_EXPONENT_BIAS)   // -127 unbiased
+#define SINGLE_EXPONENT_INF_OR_NAN  (SINGLE_EXPONENT_BIAS+1)  // 128  unbiased
+
+
+// --------- Double Precision ----------
+#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
+#define DOUBLE_NUM_EXPONENT_BITS    (11)
+#define DOUBLE_NUM_SIGN_BITS        (1)
+
+#define DOUBLE_SIGNIFICAND_SHIFT    (0)
+#define DOUBLE_EXPONENT_SHIFT       (DOUBLE_NUM_SIGNIFICAND_BITS)
+#define DOUBLE_SIGN_SHIFT           (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
+
+#define DOUBLE_SIGNIFICAND_MASK     (0xfffffffffffffULL) // The lower 52 bits
+#define DOUBLE_EXPONENT_MASK        (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
+#define DOUBLE_SIGN_MASK            (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
+#define DOUBLE_QUIET_NAN_BIT        (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
+
+
+/* Biased      Biased   Unbiased  Use
+   0x00000000     0     -1023     0 and subnormal
+   0x00000001     1     -1022     Smallest normal exponent
+   0x000007fe  2046      1023     Largest normal exponent
+   0x000007ff  2047      1024     NaN and Infinity  */
+#define DOUBLE_EXPONENT_BIAS        (1023)
+#define DOUBLE_EXPONENT_MAX         (DOUBLE_EXPONENT_BIAS)    // unbiased
+#define DOUBLE_EXPONENT_MIN         (-DOUBLE_EXPONENT_BIAS+1) // unbiased
+#define DOUBLE_EXPONENT_ZERO        (-DOUBLE_EXPONENT_BIAS)   // unbiased
+#define DOUBLE_EXPONENT_INF_OR_NAN  (DOUBLE_EXPONENT_BIAS+1)  // unbiased
+
+
+
+/*
+ Convenient functions to avoid type punning, compiler warnings and such
+ The optimizer reduces them to a simple assignment.
+ This is a crusty corner of C. It shouldn't be this hard.
+ 
+ These are also in UsefulBuf.h under a different name. They are copied
+ here because to avoid a dependency on UsefulBuf.h. There is no
+ object code size impact because these always optimze down to a
+ simple assignment.
+ */
+static inline uint32_t CopyFloatToUint32(float f)
+{
+    uint32_t u32;
+    memcpy(&u32, &f, sizeof(uint32_t));
+    return u32;
+}
+
+static inline uint64_t CopyDoubleToUint64(double d)
+{
+    uint64_t u64;
+    memcpy(&u64, &d, sizeof(uint64_t));
+    return u64;
+}
+
+static inline double CopyUint64ToDouble(uint64_t u64)
+{
+    double d;
+    memcpy(&d, &u64, sizeof(uint64_t));
+    return d;
+}
+
+static inline float CopyUint32ToFloat(uint32_t u32)
+{
+    float f;
+    memcpy(&f, &u32, sizeof(uint32_t));
+    return f;
+}
+
+
+
+// Public function; see ieee754.h
+uint16_t IEEE754_FloatToHalf(float f)
+{
+    // Pull the three parts out of the single-precision float
+    const uint32_t uSingle = CopyFloatToUint32(f);
+    const int32_t  nSingleUnbiasedExponent = ((uSingle & SINGLE_EXPONENT_MASK) >> SINGLE_EXPONENT_SHIFT) - SINGLE_EXPONENT_BIAS;
+    const uint32_t uSingleSign             =  (uSingle & SINGLE_SIGN_MASK) >> SINGLE_SIGN_SHIFT;
+    const uint32_t uSingleSignificand      =   uSingle & SINGLE_SIGNIFICAND_MASK;
+    
+    
+    // Now convert the three parts to half-precision.
+    uint16_t uHalfSign, uHalfSignificand, uHalfBiasedExponent;
+    if(nSingleUnbiasedExponent == SINGLE_EXPONENT_INF_OR_NAN) {
+        // +/- Infinity and NaNs -- single biased exponent is 0xff
+        uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS;
+        if(!uSingleSignificand) {
+            // Infinity
+            uHalfSignificand = 0;
+        } else {
+            // Copy the LBSs 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 a 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.
+                    uHalfSignificand |= 0x01;
+                }
+            }
+        }
+    } else if(nSingleUnbiasedExponent == SINGLE_EXPONENT_ZERO) {
+        // 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
+        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
+        uHalfBiasedExponent = (uint16_t)(HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS);
+        // Difference between single normal exponent and the base exponent of a half subnormal
+        const uint32_t nExpDiff = -(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 int32_t nSignificandBitsDiff = 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 + (0x01L << SINGLE_NUM_SIGNIFICAND_BITS);
+        uHalfSignificand = uSingleSignificandSubnormal >> (nExpDiff + nSignificandBitsDiff);
+    } else {
+        // The normal case
+        uHalfBiasedExponent = nSingleUnbiasedExponent + HALF_EXPONENT_BIAS;
+        uHalfSignificand    = uSingleSignificand >> (SINGLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
+    }
+    uHalfSign = uSingleSign;
+
+    // Put the 3 values in the right place for a half precision
+    const uint16_t uHalfPrecision =  uHalfSignificand |
+                                    (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) |
+                                    (uHalfSign << HALF_SIGN_SHIFT);
+    return uHalfPrecision;
+}
+
+
+// Public function; see ieee754.h
+uint16_t IEEE754_DoubleToHalf(double d)
+{
+    // Pull the three parts out of the double-precision float
+    const uint64_t uDouble = CopyDoubleToUint64(d);
+    const int64_t  nDoubleUnbiasedExponent = ((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS;
+    const uint64_t uDoubleSign             =  (uDouble & DOUBLE_SIGN_MASK) >> DOUBLE_SIGN_SHIFT;
+    const uint64_t uDoubleSignificand      =   uDouble & DOUBLE_SIGNIFICAND_MASK;
+
+    
+    // Now convert the three parts to half-precision.
+    uint16_t uHalfSign, uHalfSignificand, uHalfBiasedExponent;
+    if(nDoubleUnbiasedExponent == DOUBLE_EXPONENT_INF_OR_NAN) {
+        // +/- Infinity and NaNs -- single biased exponent is 0xff
+        uHalfBiasedExponent = HALF_EXPONENT_INF_OR_NAN + HALF_EXPONENT_BIAS;
+        if(!uDoubleSignificand) {
+            // Infinity
+            uHalfSignificand = 0;
+        } else {
+            // Copy the LBSs 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
+                if(!uHalfSignificand) {
+                    // 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
+        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?
+        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
+        uHalfBiasedExponent = (uint16_t)(HALF_EXPONENT_ZERO + HALF_EXPONENT_BIAS);
+        // Difference between double normal exponent and the base exponent of a half subnormal
+        const uint64_t nExpDiff = -(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 int64_t nSignificandBitsDiff = 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 + (0x01L << DOUBLE_NUM_SIGNIFICAND_BITS);
+        uHalfSignificand = uDoubleSignificandSubnormal >> (nExpDiff + nSignificandBitsDiff);
+    } else {
+        // The normal case
+        uHalfBiasedExponent = nDoubleUnbiasedExponent + HALF_EXPONENT_BIAS;
+        uHalfSignificand    = uDoubleSignificand >> (DOUBLE_NUM_SIGNIFICAND_BITS - HALF_NUM_SIGNIFICAND_BITS);
+    }
+    uHalfSign = uDoubleSign;
+    
+    
+    // Put the 3 values in the right place for a half precision
+    const uint16_t uHalfPrecision =  uHalfSignificand |
+                                    (uHalfBiasedExponent << HALF_EXPONENT_SHIFT) |
+                                    (uHalfSign << HALF_SIGN_SHIFT);
+    return uHalfPrecision;
+}
+
+
+// Public function; see ieee754.h
+float IEEE754_HalfToFloat(uint16_t uHalfPrecision)
+{
+    // Pull out the three parts of the half-precision float
+    const uint16_t uHalfSignificand      =   uHalfPrecision & HALF_SIGNIFICAND_MASK;
+    const int16_t  nHalfUnBiasedExponent = ((uHalfPrecision & HALF_EXPONENT_MASK) >> HALF_EXPONENT_SHIFT) - HALF_EXPONENT_BIAS;
+    const uint16_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 = 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);
+}
+
+
+/*
+ double IEEE754_HalfToDouble(uint16_t uHalfPrecision) is not needed
+*/
+
+
+
+// Public function; see ieee754.h
+IEEE754_union IEEE754_FloatToSmallest(float f)
+{
+    IEEE754_union result;
+    
+    // Pull the neeed two parts out of the single-precision float
+    const uint32_t uSingle = CopyFloatToUint32(f);
+    const int32_t  nSingleExponent    = ((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
+    const uint64_t uDroppedSingleBits = SINGLE_SIGNIFICAND_MASK >> HALF_NUM_SIGNIFICAND_BITS;
+
+    // Optimizer will re organize so there is only one call to IEEE754_FloatToHalf()
+    if(uSingle == 0) {
+        // Value is 0.0000, not a a subnormal
+        result.uTag = IEEE754_UNION_IS_HALF;
+        result.u16  = IEEE754_FloatToHalf(f);
+    } else if(nSingleExponent == SINGLE_EXPONENT_INF_OR_NAN) {
+        // NaN, +/- infinity
+        result.uTag = IEEE754_UNION_IS_HALF;
+        result.u16  = IEEE754_FloatToHalf(f);
+    } else if((nSingleExponent >= HALF_EXPONENT_MIN) && nSingleExponent <= HALF_EXPONENT_MAX && (!(uSingleSignificand & uDroppedSingleBits))) {
+        // Normal number in exponent range and precision won't be lost
+        result.uTag = IEEE754_UNION_IS_HALF;
+        result.u16  = IEEE754_FloatToHalf(f);
+    } else {
+        // Subnormal, exponent out of range, or precision will be lost
+        result.uTag = IEEE754_UNION_IS_SINGLE;
+        result.u32  = uSingle;
+    }
+    
+    return result;
+}
+
+// Public function; see ieee754.h
+IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision)
+{
+    IEEE754_union result;
+    
+    // Pull the needed two parts out of the double-precision float
+    const uint64_t uDouble = CopyDoubleToUint64(d);
+    const int64_t  nDoubleExponent     = ((uDouble & DOUBLE_EXPONENT_MASK) >> DOUBLE_EXPONENT_SHIFT) - DOUBLE_EXPONENT_BIAS;
+    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 uDroppedSingleBits = DOUBLE_SIGNIFICAND_MASK >> SINGLE_NUM_SIGNIFICAND_BITS;
+        
+    // The various cases
+    if(d == 0.0) { // Take care of positive and negative zero
+        // Value is 0.0000, not a a subnormal
+        result.uTag = IEEE754_UNION_IS_HALF;
+        result.u16  = IEEE754_DoubleToHalf(d);
+    } else if(nDoubleExponent == DOUBLE_EXPONENT_INF_OR_NAN) {
+        // NaN, +/- infinity
+        result.uTag = IEEE754_UNION_IS_HALF;
+        result.u16  = IEEE754_DoubleToHalf(d);
+    } else if(bAllowHalfPrecision && (nDoubleExponent >= HALF_EXPONENT_MIN) && nDoubleExponent <= HALF_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedDoubleBits))) {
+        // Can convert to half without precision loss
+        result.uTag = IEEE754_UNION_IS_HALF;
+        result.u16  = IEEE754_DoubleToHalf(d);
+    } else if((nDoubleExponent >= SINGLE_EXPONENT_MIN) && nDoubleExponent <= SINGLE_EXPONENT_MAX && (!(uDoubleSignificand & uDroppedSingleBits))) {
+        // Can convert to single without precision loss
+        result.uTag = IEEE754_UNION_IS_SINGLE;
+        result.u32  = CopyFloatToUint32((float)d);
+    } else {
+        // Can't convert without precision loss
+        result.uTag = IEEE754_UNION_IS_DOUBLE;
+        result.u64  = uDouble;
+    }
+    
+    return result;
+}
+
diff --git a/src/ieee754.h b/src/ieee754.h
new file mode 100644
index 0000000..f6824ba
--- /dev/null
+++ b/src/ieee754.h
@@ -0,0 +1,193 @@
+/*==============================================================================
+ Copyright 2018 Laurence Lundblade
+ 
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ 
+ (This is the MIT license)
+ ==============================================================================*/
+//
+//  ieee754.h
+//  Indefinite
+//
+//  Created by Laurence Lundblade on 7/23/18.
+//  Copyright © 2018 Laurence Lundblade. All rights reserved.
+//
+
+#ifndef ieee754_h
+#define ieee754_h
+
+#include <stdint.h>
+
+
+
+/*
+ General comments
+ 
+ This is a complete in that it handles all conversion cases
+ including +/- infinity, +/- zero, subnormal numbers, qNaN, sNaN
+ and NaN payloads.
+ 
+ This confirms to IEEE 754-2008, but note that this doesn't
+ specify conversions, just the encodings.
+ 
+ NaN payloads are preserved with alignment on the LSB. The
+ qNaN bit is handled differently and explicity copied. It
+ is always the MSB of the significand. The NaN payload MSBs
+ (except the qNaN bit) are truncated when going from
+ double or single to half.
+ 
+ TODO: what does the C cast do with NaN payloads from
+ double to single?
+ 
+ 
+ 
+ */
+
+/*
+ Most simply just explicilty encode the type you want, single or double.
+ This works easily everywhere since standard C supports both
+ these types and so does qcbor.  This encoder also supports
+ half precision and there's a few ways to use it to encode
+ floating point numbers in less space.
+ 
+ Without losing precision, you can encode a single or double
+ such that the special values of 0, NaN and Infinity encode
+ as half-precision.  This CBOR decodoer and most others
+ should handle this properly.
+ 
+ If you don't mind losing precision, then you can use half-precision.
+ One way to do this is to set up your environment to use
+ ___fp_16. Some compilers and CPUs support it even though it is not
+ standard C. What is nice about this is that your program
+ will use less memory and floating point operations like
+ multiplying, adding and such will be faster.
+ 
+ Another way to make use of half-precision is to represent
+ the values in your program as single or double, but encode
+ them in CBOR as half-precision. This cuts the size
+ of the encoded messages by 2 or 4, but doesn't reduce
+ memory needs or speed because you are still using
+ single or double in your code.
+ 
+
+ encode:
+    - float as float
+    - double as double
+    - half as half
+ - float as half_precision, for environments that don't support a half-precision type
+ - double as half_precision, for environments that don't support a half-precision type
+ - float with NaN, Infinity and 0 as half
+ - double with NaN, Infinity and 0 as half
+ 
+ 
+ 
+ 
+ */
+
+
+
+/*
+ Convert single 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.
+ */
+uint16_t IEEE754_FloatToHalf(float f);
+
+
+/*
+ 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.
+ */
+uint16_t IEEE754_DoubleToHalf(double d);
+
+
+/*
+ Convert half precision float to double precision float.
+ This is a loss-less conversion.
+ */
+double IEEE754_HalfToDouble(uint16_t uHalfPrecision);
+
+
+
+
+#define IEEE754_UNION_IS_HALF   0
+#define IEEE754_UNION_IS_SINGLE 1
+#define IEEE754_UNION_IS_DOUBLE 2
+
+typedef struct {
+    uint8_t uTag;  // One of IEEE754_IS_xxxx
+    union {
+        uint16_t u16;
+        uint32_t u32;
+        uint64_t u64;
+    };
+} IEEE754_union;
+
+
+/*
+ Converts double-precision to single-precision or half-precision if possible without
+ loss of precisions. If not, leaves it as a double. Only converts to single-precision
+ unless bAllowHalfPrecision is set.
+ */
+IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision);
+
+/*
+ Converts double-precision to single-precision if possible without
+ loss of precision. If not, leaves it as a double.
+ */
+static inline IEEE754_union IEEE754_DoubleToSmall(double d)
+{
+    return IEEE754_DoubleToSmallestInternal(d, 0);
+}
+
+
+/*
+ Converts double-precision to single-precision or half-precision if possible without
+ loss of precisions. If not, leaves it as a double.
+ */
+static inline IEEE754_union IEEE754_DoubleToSmallest(double d)
+{
+    return IEEE754_DoubleToSmallestInternal(d, 1);
+}
+
+/*
+ Converts single-precision to half-precision if possible without
+ loss of precision. If not leaves as single-precision.
+ */
+IEEE754_union IEEE754_FloatToSmallest(float f);
+
+
+#endif /* ieee754_h */
+
+
+
+
+
+
+
diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c
index 1d6fd58..7e441cd 100644
--- a/src/qcbor_decode.c
+++ b/src/qcbor_decode.c
@@ -75,6 +75,7 @@
  =====================================================================================*/
 
 #include "qcbor.h"
+#include "ieee754.h"
 
 
 
@@ -326,6 +327,17 @@
       case CBOR_SIMPLE_BREAK:  // 31
          nReturn = QCBOR_ERR_UNSUPPORTED;
          break;
+           
+      case HALF_PREC_FLOAT:
+         pDecodedItem->val.fnum  = IEEE754_HalfToFloat((uint16_t)uNumber);
+         pDecodedItem->uDataType = QCBOR_TYPE_FLOAT;
+         break;
+      case SINGLE_PREC_FLOAT:
+         pDecodedItem->val.fnum = UsefulBufUtil_CopyUint32ToFloat((uint32_t)uNumber);
+         break;
+      case DOUBLE_PREC_FLOAT:
+         pDecodedItem->val.dfnum = UsefulBufUtil_CopyUint64ToDouble(uNumber);
+         break;
          
       case CBOR_SIMPLEV_FALSE: // 20
       case CBOR_SIMPLEV_TRUE:  // 21
diff --git a/src/qcbor_encode.c b/src/qcbor_encode.c
index 3ad809e..ece04e4 100644
--- a/src/qcbor_encode.c
+++ b/src/qcbor_encode.c
@@ -76,6 +76,7 @@
  =====================================================================================*/
 
 #include "qcbor.h"
+#include "ieee754.h"
 
 
 /*...... This is a ruler that is 80 characters long...........................*/
@@ -279,7 +280,7 @@
    // always generated internally, not by the caller, b) this is for CBOR
    // _generation_, not parsing c) a mistake will result in bad CBOR generation,
    // not a security vulnerability.
-   uMajorType <<= 5;
+   uMajorType <<= 5; // TODO: make this a constant
    
    if(uNumber > 0xffffffff || uMinLen >= 8) {
       UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_EIGHT_BYTES, uPos);
@@ -289,7 +290,7 @@
       UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_FOUR_BYTES, uPos);
       UsefulOutBuf_InsertUint32(&(me->OutBuf), (uint32_t)uNumber, uPos+1);
       
-   } else if (uNumber > 0xff) {
+   } else if (uNumber > 0xff || uMinLen>= 2) {
       // Between 0 and 65535
       UsefulOutBuf_InsertByte(&(me->OutBuf), uMajorType + LEN_IS_TWO_BYTES, uPos);
       UsefulOutBuf_InsertUint16(&(me->OutBuf), (uint16_t)uNumber, uPos+1);
@@ -606,6 +607,35 @@
    AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(double), uNum);
 }
 
+void QCBOREncode_AddFloatAsHalf_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, float fNum)
+{
+    AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(uint16_t), IEEE754_FloatToHalf(fNum));
+}
+
+static void QCBOREncode_AddFUnionAsSmallest_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, IEEE754_union uNum)
+{
+   switch(uNum.uTag) {
+      case IEEE754_UNION_IS_HALF:
+         AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(uint16_t), uNum.u16);
+         break;
+      case IEEE754_UNION_IS_SINGLE:
+         AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(uint32_t), uNum.u32);
+         break;
+      case IEEE754_UNION_IS_DOUBLE:
+         AddSimpleInternal(me, szLabel, nLabel, uTag, sizeof(uint64_t), uNum.u64);
+         break;
+   }
+}
+
+void QCBOREncode_AddFloatAsSmallest_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, float fNum)
+{
+   QCBOREncode_AddFUnionAsSmallest_3(me, szLabel, nLabel, uTag, IEEE754_FloatToSmallest(fNum));
+}
+
+void QCBOREncode_AddDoubleAsSmallest_3(QCBOREncodeContext *me, const char *szLabel, int64_t nLabel, uint64_t uTag, double dNum)
+{
+   QCBOREncode_AddFUnionAsSmallest_3(me, szLabel, nLabel, uTag, IEEE754_DoubleToSmallest(dNum));
+}
 
 
 
diff --git a/test/basic_test.c b/test/basic_test.c
index e58ff85..508c6fd 100644
--- a/test/basic_test.c
+++ b/test/basic_test.c
@@ -1,30 +1,32 @@
-/*
-  basic_test.c -- basic tests for qcbor encoder / decoder
+/*==============================================================================
+ basic_test.c -- most basic test for QCBOR
  
-  This is governed by the MIT license.
+ Copyright 2018 Laurence Lundblade
  
-  Copyright 2018 Laurence Lundblade
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
  
-  Permission is hereby granted, free of charge, to any person obtaining
-  a copy of this software and associated documentation files (the
-  "Software"), to deal in the Software without restriction, including
-  without limitation the rights to use, copy, modify, merge, publish,
-  distribute, sublicense, and/or sell copies of the Software, and to
-  permit persons to whom the Software is furnished to do so, subject to
-  the following conditions:
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
  
-  The above copyright notice and this permission notice shall be included
-  in all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
  
-  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-  ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-  SOFTWARE.
- */
+ (This is the MIT license)
+ ==============================================================================*/
+//  Created by Laurence Lundblade on 9/13/18.
+
 
 #include "basic_test.h"
 #include "qcbor.h"
@@ -136,4 +138,3 @@
 
 
 
-
diff --git a/test/basic_test.h b/test/basic_test.h
index da5849f..cde44ba 100644
--- a/test/basic_test.h
+++ b/test/basic_test.h
@@ -1,7 +1,5 @@
-/*
- basic_test.h -- basic tests for qcbor encoder / decoder
- 
- This is governed by the MIT license.
+/*==============================================================================
+ basic_test.h -- most basic test for QCBOR
  
  Copyright 2018 Laurence Lundblade
  
@@ -26,6 +24,8 @@
  SOFTWARE.
  */
 
+//  Created by Laurence Lundblade on 9/13/18.
+
 #ifndef basic_test_h
 #define basic_test_h
 
diff --git a/test/bstrwrap_tests.c b/test/bstrwrap_tests.c
index a000377..7c6621b 100644
--- a/test/bstrwrap_tests.c
+++ b/test/bstrwrap_tests.c
@@ -122,44 +122,43 @@
 // Part of bstr_wrap_nest_test
 /*
  83 array with three
- 53  byte string with 19 bytes
- 01  #1
- 50 byte string with 16 bytes
- 02
- 4D byte string with 13 bytes
- 03
- 4A byte string with 10 bytes
- 04
- 47 byte string with 7 bytes
- 05
- 44 byte string with 4 bytes
- 06
- 41 byte string with 1 byte
- 07
- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 
- A2 map with two items
- 18 20  label for byte string
- 54 byte string of length 20
- 82 Array with two items
- 10  The integer value 10
- A2 map with two items
- 18 21 label for byte string
- 44 byte string with 4 bytes
- 81 array with 1 item
- 11 integer value 11
- 18 30 integer value 30
- 18 40 integer label 40
- 65 68 65 6C 6C 6F text string hello
- 18 31 integer value 31
- 18 41 integer label 41
- 65 68 65 6C 6C 6F text string hello
+   53  byte string with 19 bytes
+      01  #1
+      50 byte string with 16 bytes
+           02
+           4D byte string with 13 bytes
+               03
+               4A byte string with 10 bytes
+                    04
+                    47 byte string with 7 bytes
+                        05
+                        44 byte string with 4 bytes
+                            06
+                            41 byte string with 1 byte
+                                 07
+                            01
+                        02
+                    03
+               04
+           05
+       06
+  07
+    A2 map with two items
+      18 20  label for byte string
+      54 byte string of length 20
+         82 Array with two items
+            10  The integer value 10
+            A2 map with two items
+               18 21 label for byte string
+               44 byte string with 4 bytes
+                  81 array with 1 item
+                     11 integer value 11
+                  18 30 integer value 30
+               18 40 integer label 40
+               65 68 65 6C 6C 6F text string hello
+         18 31 integer value 31
+      18 41 integer label 41
+      65 68 65 6C 6C 6F text string hello
  
  
  */
diff --git a/test/half_precision_test.c b/test/half_precision_test.c
new file mode 100644
index 0000000..936d70f
--- /dev/null
+++ b/test/half_precision_test.c
@@ -0,0 +1,519 @@
+/*==============================================================================
+ half_precision_test.c -- tests for converstion to/from half-precision
+
+ Copyright 2018 Laurence Lundblade
+ 
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ 
+ (This is the MIT license)
+ ==============================================================================*/
+//  Created by Laurence Lundblade on 9/19/18.
+
+
+#include "half_precision_test.h"
+#include "qcbor.h"
+#include "half_to_double_from_rfc7049.h"
+#include <math.h> // For INFINITY and NAN and isnan()
+
+static const uint8_t ExpectedHalf[] = {
+    0xB1,
+        0x64,
+            0x7A, 0x65, 0x72, 0x6F,
+        0xF9, 0x00, 0x00,   // 0.000
+        0x6A,
+            0x69, 0x6E, 0x66, 0x69, 0x6E, 0x69, 0x74, 0x69, 0x74, 0x79,
+        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
+        0x63,
+            0x4E, 0x61, 0x4E,
+        0xF9, 0x7E, 0x00,   // NaN
+        0x63,
+            0x6F, 0x6E, 0x65,
+        0xF9, 0x3C, 0x00,   // 1.0
+        0x69,
+            0x6F, 0x6E, 0x65, 0x20, 0x74, 0x68, 0x69, 0x72, 0x64,
+        0xF9, 0x35, 0x55,   // 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
+        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
+        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
+        0x71,
+            0x62, 0x69, 0x67, 0x67, 0x65, 0x73, 0x74, 0x20, 0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C,
+        0xF9, 0x04, 0x00,   // 0.000061988
+        0x70,
+            0x73, 0x75, 0x62, 0x6E, 0x6F, 0x72, 0x6D, 0x61, 0x6C, 0x20, 0x73, 0x69, 0x6E, 0x67, 0x6C, 0x65,
+        0xF9, 0x00, 0x00,
+        0x03,
+        0xF9, 0xC0, 0x00,    // -2
+        0x04,
+        0xF9, 0x7E, 0x00,    // qNaN
+        0x05,
+        0xF9, 0x7C, 0x01,    // sNaN
+        0x06,
+        0xF9, 0x7E, 0x0F,    // qNaN with payload 0x0f
+        0x07,
+        0xF9, 0x7C, 0x0F,    // sNaN with payload 0x0f
+    
+};
+
+
+
+int half_precision_encode_basic()
+{
+    UsefulBuf_MakeStackUB(EncodedHalfsMem, 250);
+
+    QCBOREncodeContext EC;
+    QCBOREncode_Init(&EC, EncodedHalfsMem);
+    // These are mostly from https://en.wikipedia.org/wiki/Half-precision_floating-point_format
+    QCBOREncode_OpenMap(&EC);
+    QCBOREncode_AddFloatAsHalfToMap(&EC, "zero", 0.00F);
+    QCBOREncode_AddFloatAsHalfToMap(&EC, "infinitity", INFINITY);
+    QCBOREncode_AddFloatAsHalfToMap(&EC, "negative infinitity", -INFINITY);
+    QCBOREncode_AddFloatAsHalfToMap(&EC, "NaN", NAN);
+    QCBOREncode_AddFloatAsHalfToMap(&EC, "one", 1.0F);
+    QCBOREncode_AddFloatAsHalfToMap(&EC, "one third", 0.333251953125F);
+    QCBOREncode_AddFloatAsHalfToMap(&EC, "largest half-precision",65504.0F);
+    // Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which is larger than 15, the largest half-precision exponent
+    QCBOREncode_AddFloatAsHalfToMap(&EC, "too-large half-precision", 65536.0F);
+    // Should convert to smallest possible half precision which is encodded as 0x00 0x01 or 5.960464477539063e-8
+    QCBOREncode_AddFloatAsHalfToMap(&EC, "smallest subnormal", 0.0000000596046448F);
+    QCBOREncode_AddFloatAsHalfToMap(&EC, "smallest normal",    0.0000610351526F); // in hex single is 0x387fffff, exponent -15, significand 7fffff
+    QCBOREncode_AddFloatAsHalfToMap(&EC, "biggest subnormal",  0.0000610351563F); // in hex single is 0x38800000, exponent -14, significand 0
+    QCBOREncode_AddFloatAsHalfToMap(&EC, "subnormal single", 4e-40F); 
+    QCBOREncode_AddFloatAsHalfToMapN(&EC, 3, -2.0F);
+    QCBOREncode_AddFloatAsHalfToMapN(&EC, 4, UsefulBufUtil_CopyUint32ToFloat(0x7fc00000L)); // qNaN
+    QCBOREncode_AddFloatAsHalfToMapN(&EC, 5, UsefulBufUtil_CopyUint32ToFloat(0x7f800001L)); // sNaN
+    QCBOREncode_AddFloatAsHalfToMapN(&EC, 6, UsefulBufUtil_CopyUint32ToFloat(0x7fc0f00fL)); // qNaN with payload
+    QCBOREncode_AddFloatAsHalfToMapN(&EC, 7, UsefulBufUtil_CopyUint32ToFloat(0x7f80f00fL)); // sNaN with payload
+    QCBOREncode_CloseMap(&EC);
+    
+    UsefulBufC EncodedHalfs;
+    int nReturn = QCBOREncode_Finish2(&EC, &EncodedHalfs);
+    if(nReturn) {
+        return -1;
+    }
+    
+    if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FromByteArrayLiteral(ExpectedHalf))) {
+        return -3;
+    }
+    
+    return 0;
+}
+
+
+int half_precision_decode_basic()
+{
+    UsefulBufC HalfPrecision = UsefulBuf_FromByteArrayLiteral(ExpectedHalf);
+    
+    QCBORDecodeContext DC;
+    QCBORDecode_Init(&DC, HalfPrecision, 0);
+    
+    QCBORItem Item;
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_MAP) {
+        return -1;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 0.0F) {
+        return -2;
+    }
+    
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != INFINITY) {
+        return -3;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != -INFINITY) {
+        return -4;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item); // TODO, is this really converting right? It is carrying payload, but this confuses things.
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || !isnan(Item.val.fnum)) {
+        return -5;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 1.0F) {
+        return -6;
+    }
+    
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 0.333251953125F) {
+        return -7;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 65504.0F) {
+        return -8;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != INFINITY) {
+        return -9;
+    }
+    
+    QCBORDecode_GetNext(&DC, &Item); // TODO: check this
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 0.0000000596046448F) {
+        return -10;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item); // TODO: check this
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 0.0000609755516F) {
+        return -11;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item); // TODO check this
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 0.0000610351563F) {
+        return -12;
+    }
+    
+    QCBORDecode_GetNext(&DC, &Item); 
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != 0) {
+        return -13;
+    }
+    
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || Item.val.fnum != -2.0F) {
+        return -14;
+    }
+
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || UsefulBufUtil_CopyFloatToUint32(Item.val.fnum) != 0x7fc00000L) {
+        return -15;
+    }
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || UsefulBufUtil_CopyFloatToUint32(Item.val.fnum) != 0x7f800001) {
+        return -16;
+    }
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || UsefulBufUtil_CopyFloatToUint32(Item.val.fnum) != 0x7fc0000f) {
+        return -17;
+    }
+    QCBORDecode_GetNext(&DC, &Item);
+    if(Item.uDataType != QCBOR_TYPE_FLOAT || UsefulBufUtil_CopyFloatToUint32(Item.val.fnum) != 0x7f80000f) {
+        return -18;
+    }
+    
+    if(QCBORDecode_Finish(&DC)) {
+        return -19;
+    }
+    
+    return 0;
+}
+
+
+int half_precision_to_float_transitive_test()
+{
+    for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 1) {
+        // Contruct the CBOR for the half-precision float by hand
+        UsefulBuf_MakeStackUB(EncodedCBORMem, 3);
+        UsefulOutBuf UOB;
+        UsefulOutBuf_Init(&UOB, EncodedCBORMem);
+        
+        const uint8_t uHalfPrecInitialByte = HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5); // 0xf9
+        UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float
+        UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP);
+        
+        
+        // Now parse the hand-constructed CBOR. This will invoke the conversion to a float
+        QCBORDecodeContext DC;
+        QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
+        
+        QCBORItem Item;
+        QCBORDecode_GetNext(&DC, &Item);
+        if(Item.uDataType != QCBOR_TYPE_FLOAT) {
+            return -1;
+        }
+        
+        //printf("%04x  QCBOR:%15.15f  \n", uHalfP,Item.val.fnum);
+
+        
+        // Now generate CBOR with the half-precision value. This will invoke the conversion from float to half
+        UsefulBuf_MakeStackUB(OtherEncodedCBORMem, 5);
+        QCBOREncodeContext EC;
+        QCBOREncode_Init(&EC, OtherEncodedCBORMem);
+        QCBOREncode_AddFloatAsHalf(&EC, Item.val.fnum);
+        UsefulBufC EnCBOR;
+        QCBOREncode_Finish2(&EC, &EnCBOR); // todo check return code
+        
+        
+        // Finally parse the CBOR by hand to get at half-precision that was actually encoded.
+        UsefulInputBuf UIB;
+        UsefulInputBuf_Init(&UIB, EnCBOR);
+        if(UsefulInputBuf_GetByte(&UIB) != uHalfPrecInitialByte) {
+            return -2;
+        }
+        if(UsefulInputBuf_GetUint16(&UIB) != uHalfP) { // the moment of truth did we get back what we started with?
+            return -3;
+        }
+    }
+    
+    return 0;
+}
+
+
+int half_precision_to_float_vs_rfc_test()
+{
+    for(uint32_t uHalfP = 0; uHalfP < 0xffff; uHalfP += 60) {
+        unsigned char x[2];
+        x[1] = uHalfP & 0xff;
+        x[0] = uHalfP >> 8;
+        double d = decode_half(x);
+        
+        // Contruct the CBOR for the half-precision float by hand
+        UsefulBuf_MakeStackUB(__xx, 3);
+        UsefulOutBuf UOB;
+        UsefulOutBuf_Init(&UOB, __xx);
+        
+        const uint8_t uHalfPrecInitialByte = HALF_PREC_FLOAT + (CBOR_MAJOR_TYPE_SIMPLE << 5); // 0xf9
+        UsefulOutBuf_AppendByte(&UOB, uHalfPrecInitialByte); // The initial byte for a half-precision float
+        UsefulOutBuf_AppendUint16(&UOB, (uint16_t)uHalfP);
+
+        // Now parse the hand-constructed CBOR. This will invoke the conversion to a float
+        QCBORDecodeContext DC;
+        QCBORDecode_Init(&DC, UsefulOutBuf_OutUBuf(&UOB), 0);
+        
+        QCBORItem Item;
+        
+        QCBORDecode_GetNext(&DC, &Item);
+        if(Item.uDataType != QCBOR_TYPE_FLOAT) {
+            return -1;
+        }
+        
+        //printf("%04x  QCBOR:%15.15f  RFC: %15.15f (%8x)\n", uHalfP,Item.val.fnum, d , UsefulBufUtil_CopyFloatToUint32(d));
+        
+        if(isnan(d)) {
+            // The RFC code uses the native instructions which may or may not
+            // handle sNaN, qNaN and NaN payloads correctly. This test just
+            // makes sure it is a NaN and doesn't worry about the type of NaN
+            if(!isnan(Item.val.fnum)) {
+                return -3;
+            }
+        } else {
+            if(Item.val.fnum != d) {
+                return -2;
+            }
+        }
+    }
+    return 0;
+}
+
+
+/*
+ {"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"}
+ 
+ */
+static const uint8_t sExpectedSmallest[] = {
+    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
+};
+
+
+
+int double_as_smallest_encode_basic()
+{
+    UsefulBuf_MakeStackUB(EncodedHalfsMem, 420);
+    
+    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);
+
+    // 64                                   # text(4)
+    //    7A65726F                          # "negative zero"
+    // F9 8000                              # primitive(0)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative zero", -0.00);
+    
+    // 6A                                   # text(10)
+    //    696E66696E6974697479              # "infinitity"
+    // F9 7C00                              # primitive(31744)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "infinitity", INFINITY);
+    
+    // 73                                   # text(19)
+    //    6E6567617469766520696E66696E6974697479 # "negative infinitity"
+    // F9 FC00                              # primitive(64512)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "negative infinitity", -INFINITY);
+    
+    // 63                                   # text(3)
+    //    4E614E                            # "NaN"
+    // F9 7E00                              # primitive(32256)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "NaN", NAN);
+    
+    // TODO: test a few NaN variants
+    
+    // 63                                   # text(3)
+    //    6F6E65                            # "one"
+    // F9 3C00                              # primitive(15360)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one", 1.0);
+    
+    // 69                                   # text(9)
+    //    6F6E65207468697264                # "one third"
+    // F9 3555                              # primitive(13653)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "one third", 0.333251953125);
+    
+    // 76                                   # text(22)
+    //    6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
+    // F9 7BFF                              # primitive(31743)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision",65504.0);
+
+    // 76                                   # text(22)
+    //    6C6172676573742068616C662D707265636973696F6E # "largest half-precision"
+    // F9 7BFF                              # primitive(31743)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "largest half-precision point one",65504.1);
+    
+    // Float 65536.0F is 0x47800000 in hex. It has an exponent of 16, which is larger than 15, the largest half-precision exponent
+    // 78 18                                # text(24)
+    //    746F6F2D6C617267652068616C662D707265636973696F6E # "too-large half-precision"
+    // FA 47800000                          # primitive(31743)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large half-precision", 65536.0);
+    
+    // The smallest possible half-precision subnormal, but digitis are lost converting
+    // to half, so this turns into a double
+    // 72                                   # text(18)
+    //    736D616C6C657374207375626E6F726D616C # "smallest subnormal"
+    // FB 3E700000001C5F68                  # primitive(4499096027744984936)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "smallest subnormal", 0.0000000596046448);
+    
+    // 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);
+    
+    // 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);
+    
+    // 03                                   # unsigned(3)
+    // F9 C000                              # primitive(49152)
+    QCBOREncode_AddDoubleAsSmallestToMapN(&EC, 3, -2.0);
+    
+    // 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
+
+    // 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);
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "too-large single exp", 5.104235503814077E+38); // Exponent too large for single
+
+    // 66                                   # text(6)
+    //    646664666465                      # "dfdfde"
+    // FA 4B800000                          # primitive(1266679808)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "biggest single with prec",16777216); // Single with no precision loss
+    
+    // 78 18                                # text(24)
+    //    626967676573742073696E676C6520776974682070726563 # "biggest single with prec"
+    // FA 4B800000                          # primitive(1266679808)
+    QCBOREncode_AddDoubleAsSmallestToMap(&EC, "first single with prec loss",16777217); // Double becuase of precision loss
+    
+    // Just a convenient marker when cutting and pasting encoded CBOR
+    QCBOREncode_AddSZStringToMapN(&EC, 1, "fin");
+
+    QCBOREncode_CloseMap(&EC);
+    
+    UsefulBufC EncodedHalfs;
+    int nReturn = QCBOREncode_Finish2(&EC, &EncodedHalfs);
+    if(nReturn) {
+        return -1;
+    }
+    
+    if(UsefulBuf_Compare(EncodedHalfs, UsefulBuf_FromByteArrayLiteral(sExpectedSmallest))) {
+        return -3;
+    }
+    
+    return 0;
+};
+
+
+
+#ifdef NAN_EXPERIMENT
+/*
+ Code for checking what the double to float cast does with
+ NaNs.  Not run as part of tests. Keep it around to
+ be able to check various platforms and CPUs.
+ */
+
+#define DOUBLE_NUM_SIGNIFICAND_BITS (52)
+#define DOUBLE_NUM_EXPONENT_BITS    (11)
+#define DOUBLE_NUM_SIGN_BITS        (1)
+
+#define DOUBLE_SIGNIFICAND_SHIFT    (0)
+#define DOUBLE_EXPONENT_SHIFT       (DOUBLE_NUM_SIGNIFICAND_BITS)
+#define DOUBLE_SIGN_SHIFT           (DOUBLE_NUM_SIGNIFICAND_BITS + DOUBLE_NUM_EXPONENT_BITS)
+
+#define DOUBLE_SIGNIFICAND_MASK     (0xfffffffffffffULL) // The lower 52 bits
+#define DOUBLE_EXPONENT_MASK        (0x7ffULL << DOUBLE_EXPONENT_SHIFT) // 11 bits of exponent
+#define DOUBLE_SIGN_MASK            (0x01ULL << DOUBLE_SIGN_SHIFT) // 1 bit of sign
+#define DOUBLE_QUIET_NAN_BIT        (0x01ULL << (DOUBLE_NUM_SIGNIFICAND_BITS-1))
+
+
+static int NaNExperiments() {
+    double dqNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT);
+    double dsNaN = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | 0x01);
+    double dqNaNPayload = UsefulBufUtil_CopyUint64ToDouble(DOUBLE_EXPONENT_MASK | DOUBLE_QUIET_NAN_BIT | 0xf00f);
+    
+    float f1 = (float)dqNaN;
+    float f2 = (float)dsNaN;
+    float f3 = (float)dqNaNPayload;
+    
+    
+    uint32_t uqNaN = UsefulBufUtil_CopyFloatToUint32((float)dqNaN);
+    uint32_t usNaN = UsefulBufUtil_CopyFloatToUint32((float)dsNaN);
+    uint32_t uqNaNPayload = UsefulBufUtil_CopyFloatToUint32((float)dqNaNPayload);
+    
+    // Result of this on x86 is that every NaN is a qNaN. The intel
+    // CVTSD2SS instruction ignores the NaN payload and even converts
+    // a sNaN to a qNaN.
+    
+    return 0;
+}
+#endif
+
+
+
diff --git a/test/half_precision_test.h b/test/half_precision_test.h
new file mode 100644
index 0000000..1367db5
--- /dev/null
+++ b/test/half_precision_test.h
@@ -0,0 +1,45 @@
+/*==============================================================================
+ half_precision_test.h -- tests for converstion to/from half-precision
+
+ Copyright 2018 Laurence Lundblade
+ 
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ 
+ (This is the MIT license)
+ ==============================================================================*/
+//  Created by Laurence Lundblade on 9/19/18.
+
+
+#ifndef half_precision_test_h
+#define half_precision_test_h
+
+int half_precision_encode_basic(void);
+
+int half_precision_decode_basic(void);
+
+int half_precision_to_float_transitive_test(void);
+
+int double_as_smallest_encode_basic(void);
+
+int half_precision_to_float_vs_rfc_test(void);
+
+
+#endif /* half_precision_test_h */
diff --git a/test/half_to_double_from_rfc7049.c b/test/half_to_double_from_rfc7049.c
new file mode 100644
index 0000000..68d03cb
--- /dev/null
+++ b/test/half_to_double_from_rfc7049.c
@@ -0,0 +1,45 @@
+/*
+ 
+ Copyright (c) 2013 IETF Trust and the persons identified as the
+ document authors.  All rights reserved.
+ 
+ This document is subject to BCP 78 and the IETF Trust's Legal
+ Provisions Relating to IETF Documents
+ (http://trustee.ietf.org/license-info) in effect on the date of
+ publication of this document.  Please review these documents
+ carefully, as they describe your rights and restrictions with respect
+ to this document.  Code Components extracted from this document must
+ include Simplified BSD License text as described in Section 4.e of
+ the Trust Legal Provisions and are provided without warranty as
+ described in the Simplified BSD License.
+ 
+ */
+
+/*
+ This code is from RFC 7049. It is not used in the main implementation
+ because:
+   a) it adds a dependency on <math.h> and ldexp().
+   b) the license may be an issue
+ 
+ QCBOR does support half-precision, but rather than using
+ floating point math like this, it does it with bit shifting
+ and masking.
+ 
+ This code is here to test that code.
+ 
+ */
+
+#include "half_to_double_from_rfc7049.h"
+
+#include <math.h>
+
+double decode_half(unsigned char *halfp) {
+    int half = (halfp[0] << 8) + halfp[1];
+    int exp = (half >> 10) & 0x1f;
+    int mant = half & 0x3ff;
+    double val;
+    if (exp == 0) val = ldexp(mant, -24);
+    else if (exp != 31) val = ldexp(mant + 1024, exp - 25);
+    else val = mant == 0 ? INFINITY : NAN;
+    return half & 0x8000 ? -val : val;
+}
diff --git a/test/half_to_double_from_rfc7049.h b/test/half_to_double_from_rfc7049.h
new file mode 100644
index 0000000..6b5f0e0
--- /dev/null
+++ b/test/half_to_double_from_rfc7049.h
@@ -0,0 +1,40 @@
+/*==============================================================================
+ Copyright 2018 Laurence Lundblade
+ 
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+ 
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+ 
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+ 
+ (This is the MIT license)
+ ==============================================================================*/
+
+//
+//  half_to_double_from_rfc7049.h
+//  QCBOR
+//
+//  Created by Laurence Lundblade on 9/23/18.
+//  Copyright © 2018 Laurence Lundblade. All rights reserved.
+//
+
+#ifndef half_to_double_from_rfc7049_h
+#define half_to_double_from_rfc7049_h
+
+double decode_half(unsigned char *halfp);
+
+#endif /* half_to_double_from_rfc7049_h */